#include "globals.h"
#include "minrexx.h"
#include "ARexxWdw.h"

extern struct RxsLib *RexxSysBase;
struct RexxMsg *LinerRexxMsg;
int LinerDispatch();

/*Function definitions private to arexx.c*/
void DoOpen(),DoSave(),DoDoubClick(),DoSetTitleMsg();
void DoGetStats(),DoPrintDisk(),DoGetChar(),DoGetWord(),DoGetLineText();
void DoCursorRight(),DoCursorLeft(),DoDoubSpacing(),DoInterlaced();
void DoIcons(),DoScrnSize(),DoStartingLevel(),DoLoadPrefs(),DoARexxSearch();
void DoInsertText();
void DoGetLine(),DoStartLine(),DoEndLine(),DoPushIn(),DoPullOut();
void DoFakeReturn(),SpecReplyToRexx();
void DoGetFilename(),DoPutPrefs();

struct rexxCommandList rcl[]= /*The list of all the ARexx commands and*/
{        /*their associated functions*/
   { "open" , (APTR)&DoOpen},
   { "save" , (APTR)&DoSave},
   { "getfilename" , (APTR)&DoGetFilename},
   { "new" , (APTR)&NewAll},
   { "printprinter", (APTR)&HandlePrintPrinter},
   { "printdisk" , (APTR)&DoPrintDisk},
   { "quit" , (APTR)&CloseStuff },
   { "doubclick" , (APTR) &DoDoubClick},
   { "settitlemsg" , (APTR) &DoSetTitleMsg},
   { "getstats" , (APTR) &DoGetStats},
   { "getchar" , (APTR) &DoGetChar},
   { "getword" , (APTR) &DoGetWord},
   { "getlinetext" , (APTR) &DoGetLineText},
   { "cut" , (APTR) &HandleCut},
   { "copy" , (APTR) &HandleCopy},
   { "paste" , (APTR) &HandlePaste},
   { "erase" , (APTR) &HandleErase},
   { "cursorup" , (APTR) &CursorUp},
   { "cursordown" , (APTR) &CursorDown},
   { "cursorright" , (APTR) &DoCursorRight},
   { "cursorleft" , (APTR) &DoCursorLeft},
   { "totop" , (APTR) &JumpToTop},
   { "tobottom" , (APTR) &JumpToBottom},
   { "upscreen" , (APTR) &WholeScreenUp},
   { "downscreen" , (APTR) &WholeScreenDown},
   { "doubspacing" , (APTR) &DoDoubSpacing},
   { "interlaced" , (APTR) &DoInterlaced},
   { "icons" , (APTR) &DoIcons },
   { "scrnsize" , (APTR)&DoScrnSize},
   { "startinglevel" , (APTR)&DoStartingLevel},
   { "loadprefs" , (APTR)&HandleReloadPrefs},
   { "sveprefs" , (APTR)&DoPutPrefs},
   { "search" , (APTR)&DoARexxSearch},
   { "instext" , (APTR)&DoInsertText},
   { "getline" , (APTR)&DoGetLine},
   { "fakereturn" , (APTR)&DoFakeReturn},
   { "fakebs" , (APTR)&HandleBS},
   { "pushin" , (APTR)&DoPushIn},
   { "pullout" , (APTR)&DoPullOut},
   { "startline" , (APTR)&DoStartLine},
   { "endline" , (APTR) &DoEndLine},
   { NULL , NULL}
};

void OpenARexx() /*Open the ARexx port*/
{
   ARexxSigBit=upRexxPort("liner",rcl,"liner",&LinerDispatch);
}

void CloseARexx() /*Close the ARexx port*/
{
   dnRexxPort();
}

void CheckRexxPort() /*Check the ARexx port for commands*/
{
   dispRexxPort();
}

int LinerDispatch(msg,rcl,p) /*The minrexx userdisp function*/
struct RexxMsg *msg;
struct rexxCommandList *rcl;
char *p;
{
   
   LinerRexxMsg=(struct RexxMsg *)msg;
   
   ((int(*)())(rcl->userdata))(p); /*Call the function associated with the */
                           /*ARexx command received*/
   
      /*If the function is one of those that returns something to ARexx*/
   if(strcmp(rcl->name,"open")==0 || strcmp(rcl->name,"printdisk")==0 ||
         strcmp(rcl->name,"getlinetext")==0 || strcmp(rcl->name,"getline")==0 ||
         strcmp(rcl->name,"getchar")==0 || strcmp(rcl->name,"linersearch")==0 ||
         strcmp(rcl->name,"getstats")==0 || strcmp(rcl->name,"getword")==0 ||
         strcmp(rcl->name,"startinglevel")==0||strcmp(rcl->name,"fakereturn")==0
         || strcmp(rcl->name,"pushin") || strcmp(rcl->name,"pullout") ||
         strcmp(rcl->name,"getfilename") || strcmp(rcl->name,"sveprefs") )
      return(1);  /*Tell minrexx not to replyRexxCmd()*/
   else
      return(0);
}   

void DoOpen(p)   /*Open a file under ARexx control*/
char *p;
{
  
   /*Setup the filename*/
   strcpy(FileName,&p[1]);
   if(ReadItemList(FileName,TRUE))  /*Do the read*/
   {
      Modified=FALSE;
      TitleErrorCancel();
      SplitFilename(FileName,SFileName,SDirName);
      replyRexxCmd(LinerRexxMsg,0,0,"true");
   }
   else
      replyRexxCmd(LinerRexxMsg,0,0,"false");
}

void DoSave(p)   /*Save a file under ARexx*/
char *p;
{
   strcpy(FileName,&p[1]);
   SplitFilename(FileName,SFileName,SDirName);
   Save();  /*Write the file out*/
}

void DoGetFilename()
{
   char filename[183];
   
   strcpy(filename,SDirName);
   if(filename[strlen(filename)-1]!=':' && filename[strlen(filename)-1]!=NULL)
      strcat(filename,"/");   /*Append a / if not at the root*/
   strcat(filename,SFileName);
   replyRexxCmd(LinerRexxMsg,0,0,filename);
}

void DoPrintDisk(p)  /*Print a file to disk*/
char *p;
{
   SplitFilename(++p,PFileName,PDirName);
   SpecReplyToRexx(HandlePrintDisk(TRUE,p),TRUE);
}

void DoDoubClick(p)  /*Fake a double click (good for highlighting blocks)*/
char *p;
{
   p++;
   PtrY=CurY;
   if(strcmp(p,"true")==0) /*if the click is meant to be outside a line*/
      PtrX=1;
   else
      PtrX=CurX;
   HandleInvs();
   BLastX=CurX;
}

void DoSetTitleMsg(p) /*Print message in 'p' in title bar*/
char *p;
{
   TitleError(&p[1]);
}

void DoGetStats()  /*Tell ARexx the CurrentItem's level, number, and */
{                    /*whether or not it's a continuation*/
   char buffer1[7];
   static char buffer2[12];
   
   stci_d(buffer2,CurrentItem->Level); /*Convert the numbers into text*/
   strcat(buffer2," ");
   stci_d(buffer1,CurrentItem->ItemNumber);
   strcat(buffer2,buffer1);
   if(CurrentItem->cont)
      strcat(buffer2," true");   /*true==continuation*/
   else
      strcat(buffer2," false");
      
   replyRexxCmd(LinerRexxMsg,0,0,buffer2);
   
      
}

void DoGetChar() /*Send the character under the cursor to ARexx*/
{
   char letter[2];
   
   letter[1]=NULL;
   letter[0]=CurrentItem->Text[PosInText(CurrentItem->Level)];/*Get the letter*/
   replyRexxCmd(LinerRexxMsg,0,0,letter);
}

void DoGetWord() /*Send the word under the cursor to ARexx*/
{
   static result[80];
   BYTE c;
   
   for(c=0;c<80;result[c++]=NULL); /*Clear the string (weird things happen*/
                     /*if I don't, and I don't know why...)*/
   strcpy(result,"");
   GetWord(result,CurrentItem);
   replyRexxCmd(LinerRexxMsg,0,0,result);
}

void DoGetLineText() /*Send the current line's text to ARexx*/
{
   static buffer[100];
   strcpy(buffer,CurrentItem->Text);
   replyRexxCmd(LinerRexxMsg,0,0,buffer);
}

void DoCursorRight()   /*Move the cursor to the right*/
{
   CursorRight(0);
}

void DoCursorLeft() /*Move the cursor to the left*/
{
   CursorLeft(0);
}

void DoDoubSpacing(p) /*Set the spacing*/
char *p;
{
   p++;
   if(strcmp(p,"true")==0) /*Set double spacing*/
   {
      if(!prefs.DS)  /*If not double spaced*/
      {
         DoubleSpacing();
         ModifyMenus(32+StartingLevel); /*Change menus appropriately*/
      }
   }
   else  /*Unset double spacing*/
      if(prefs.DS) /*If double spaced*/
      {
         DoubleSpacing();
         ModifyMenus(StartingLevel);
      }
}

void DoInterlaced(p) /*Determine whether the screen is/isn't interlaced*/
char *p;
{
   p++;
   
   if(!prefs.Laced)   /*If interlaced*/
   {
      if(strcmp(p,"true")==0) /*Switch to non-interlaced*/
      {
         HandleInterlaced();
         ModifyOtherMenus(1);
      }
   }
   else
      if(strcmp(p,"false")==0)   /*Switch to interlaced*/
      {
         HandleInterlaced();
         ModifyOtherMenus(1);
      }
   
}

void DoIcons(p)   /*Set program to create/not create icons*/
char *p;
{
   p++;
   if(((prefs.Icons) && (strcmp(p,"false")==0)) ||
         ((!prefs.Icons) && (strcmp(p,"true")==0) ) )
   {
      ModifyOtherMenus(2); /*Modify the menu flag*/
      HandleIcons();
   }
}

void DoScrnSize(p)   /*Set the screen size (workbench or standard)*/
char *p;
{
   p++;
   
   if( ( (prefs.Screen == 0) && (strcmp(p,"workbench")==0) ) ||
         ( (prefs.Screen == 1) && (strcmp(p,"standard")==0) ) )
   {
      ModifyOtherMenus(3); /*Modify the menu flag*/
      SwapScrnSize();      /*Change the screen size*/
   }
}

void DoStartingLevel(p) /*Set the starting level*/
char *p;
{
   int level;
   p++;
   p[1]=NULL;
   stcd_i(p,&level); /*Get the level (as a number)*/
   if(level < 0 || level > 5)
      SpecReplyToRexx(FALSE);
   if(level == StartingLevel)
      SpecReplyToRexx(TRUE);
      
   if(prefs.DS)   /*If double spaced*/
      level+=32;  /*Alter level for ModifyMenus()*/
   ModifyMenus(level);
   StartingLevel=level; /*Record the new starting level*/
   Refresh();  /*And update the display*/
      SpecReplyToRexx(TRUE);
   
}

void DoARexxSearch(p)   /*Do a search/replace*/
char *p;
{
   BYTE cse,partial,repl,c,i,old;
   char search[80],replace[80];
   search[0]=replace[0]=NULL;
   
   for(c=0;c<80;search[c++]=NULL)
      replace[c]=NULL;
   
   cse=Interp(p[1]);
   partial=Interp(p[2]);
   repl=Interp(p[3]);
   
   if(!(p[4]==NULL || p[5]==NULL)) /*If there is a word to search for*/
   {     /*use it.  Otherwise, use what the user has specified*/
      for(c=5,i=0;p[c] != NULL && p[c]!=' ';i++,c++);
      strncpy(search,&p[5],i);
      if(p[c]!=NULL && p[c+1]!=NULL)
      {
         for(old=++c,i=0;p[c]!=NULL && p[c]!=' ';++i,c++);
         strncpy(replace,&p[old],i);
      }
   }
   
   /*Set the appropriate search variables*/
   ModifyParams(search,replace,cse,partial,repl);
   if(DoSearch(TRUE,TRUE))  /*Do the actual search*/
      strcpy(search,"true");
   else
      strcpy(search,"false");
      
   /*Give ARexx the result*/
   replyRexxCmd(LinerRexxMsg,0,0,search);

}

Interp(p)   /*Used by DoARexxSearch.  Determines if a parameter send by ARexx*/
char p;  /*specified setting a search variable to TRUE, FALSE, or leaving it*/
{        /*unchanged*/
   switch(p)
   {
      case 't':
      case 'T':
         return(TRUE);
      case 'f':
      case 'F':
         return(FALSE);
      case 'u':
      case 'U':
         return(100);   /*Unchanged*/
   }
   return(100);   /*If none of the above, something's screwy.  Best to not*/
}                    /*change anything*/

void DoInsertText(p) /*Insert a text string into the line after the cursor*/
char *p;
{
   char WorkString[160];
   UBYTE TempX;
   
   WorkString[0]=NULL;
   
   strcpy(WorkString,CurrentItem->Text);
   WorkString[PosInText(CurrentItem->Level)]=NULL;
   strcat(WorkString,&p[1]);
   strcat(WorkString,&CurrentItem->Text[PosInText(CurrentItem->Level)]);
   WorkString[MaxLen(CurrentItem->Level)]=NULL;
   strcpy(CurrentItem->Text,WorkString);
   TempX=CurX;
   PlotCursor(1,CurY);
   PrintItem(CurrentItem);
   PlotCursor(TempX,CurY);

}

void DoGetLine() /*Return an entire line to ARexx (incl. line number)*/
{
   static buffer[100];  /*static to make sure it doesn't disappear before*/

   MakeTextLine(buffer,CurrentItem); /*ARexx gets it*/
   buffer[strlen(CurrentItem->Text)-1]=NULL;
   replyRexxCmd(LinerRexxMsg,0,0,buffer);
}

void DoFakeReturn(p) /*Let ARexx push the return button (i.e. create a line)*/
char *p;
{
   BYTE stat;
   p++;
   if(strcmp(p,"shift")==0)
      stat=HandleReturn(3);
   else
      stat=HandleReturn(0);
   SpecReplyToRexx(stat);
}

void DoStartLine()
{
   CursorLeft(8); /*Fake a SHIFT-CURSOR-LEFT*/
}

void DoEndLine()
{
   CursorRight(8); /*Fake a SHIFT-CURSOR-RIGHT*/
}

void DoPushIn()   /*Fake a TAB*/
{
   SpecReplyToRexx(HandleTAB(0));
}

void DoPullOut()  /*Fake a SHIFT-TAB*/
{
   SpecReplyToRexx(HandleTAB(3));
}

void DoPutPrefs()
{
   SpecReplyToRexx(PutPrefs("liner:liner.prefs",TRUE));
}

void SpecReplyToRexx(stat) /*Send a 'true' or 'false' to ARexx*/
BYTE stat;
{
   if(stat)
      replyRexxCmd(LinerRexxMsg,0,0,"true");
   else
      replyRexxCmd(LinerRexxMsg,0,0,"false");
}

void GetWord(result,item) /*Get the word under the cursor*/
char *result;
struct LineItem *item;
{
   BYTE start,end,pos;
   
   pos=PosInText(CurrentItem->Level);
   if(pos>=strlen(CurrentItem->Text))
   {
      strcpy(result,"");
      return;
   }
   
   start=pos;
   if(pos!=0)
      for(start--;CurrentItem->Text[start]!=' ' && start >= 0;start--);
      
   if(CurrentItem->Text[pos]!=NULL) /*Not at the end of the line...*/
      for(end=pos;CurrentItem->Text[end]!=' ' && CurrentItem->Text[end]!=NULL;
            end++);
            
   strncpy(result,&CurrentItem->Text[start+1],end-start);
}

void EngageMacro(name) /*Start an external ARexx macro ('ENGAGE!' - J-LP :-)*/
char *name;
{  
   asyncRexxCmd(name);
}

void GetMacroInfo() /*Open the window to get the macro names*/
{
   struct Window *MacroWdw;
   struct IntuiMessage *mesg;
   struct Gadget *gadg;
   char Name[4][80],Macro[4][80];
   BYTE c;
   
   for(c=0;c<4;c++) /*Store the Names and Macro filename in case CANCEL*/
   {                 /*gets pushed*/
      strcpy(Name[c],prefs.Name[c]);
      strcpy(Macro[c],prefs.Macro[c]);
   }
   
   NewWindowStructure1.Screen=(struct Screen *) Screen;
   MacroWdw=(struct Window *)OpenWindow(&NewWindowStructure1);
   if(MacroWdw==NULL)
   {
      Leave(0,"Couldn't open the window!");
      return;
   }
      
   PrintIText(MacroWdw->RPort,&IntuiTextList1,0,0); /*Print the text*/
   
   Wait(1<<MacroWdw->UserPort->mp_SigBit);   /*Wait for Done to be pressed*/
   
   mesg=(struct IntuiMessage *)GetMsg(MacroWdw->UserPort);
   gadg=(APTR)mesg->IAddress;
   ReplyMsg(mesg);
   
   if(gadg->GadgetID == 10) /*Cancel was pressed*/
      for(c=0;c<4;c++)
      {
         strcpy(prefs.Name[c],Name[c]);
         strcpy(prefs.Macro[c],Macro[c]);
      }
   else  /*OK*/
      CopyPrefsToMenus();
   
   CloseWindow(MacroWdw);
}

void SplitFilename(Filename,file,dir) /*Split a full filename into */
char *Filename,*file,*dir; /*path, filename, and extension*/
{
   char path[150];
   char ext[150];
   
   strsfn(Filename,dir,path,file,ext);
   strcat(dir,path);
   strcpy(file,&Filename[strlen(dir)+((Filename[strlen(dir)]=='/') ? 1 : 0)]);
/*   strcat(file,ext); */
}

/*End of arexx.c*/
