/*                                 Search.c                                */
/*The routines in this module handle the search/replace functions of 'Liner*/

#include "Globals.h"
#include "SearchWdws.h"

#define MAYBE 2
#define NONONO 3

struct SearchParameters
{
   char Search[80],Replace[80];
   BYTE rep,cse,partial;
};

struct SearchParameters parameters =
{
   "","",FALSE,FALSE,TRUE
};

struct Window *SearchWdw,*ReplAllWdw;

GetSRParameters()  /*Opens a window to get the parameters for Search/Replace*/
{
   int status;
         
   NewSearchWindow.Screen=(struct Screen *)Screen;
   SearchWdw=(struct Window *)OpenWindow(&NewSearchWindow);
   if(SearchWdw==NULL)
   {
      Leave(0,"Can't open the search/replace window!");
      return(FALSE);
   }
   PrintIText(SearchWdw->RPort,&IntuiTextList1,0,0);
   ActivateGadget(&SearchFor,SearchWdw,NULL);
         /*Activate the Search for... text gadget*/
   
   while((status=MonitorButtons())==NONONO); /*Let user enter info*/
   
   if(status) /*OK, Cancel, or Wait*/
   {
      parameters.rep = !((SrchRplc.Flags & SELECTED)==FALSE);
      parameters.partial = ((PartialWord.Flags & SELECTED)==FALSE);
      parameters.cse = !((CaseSensitive.Flags & SELECTED)==FALSE);
      strcpy(parameters.Search,SearchForSInfo.Buffer);
      strcpy(parameters.Replace,ReplaceWithSInfo.Buffer);
      if(status==MAYBE)
         status=FALSE;
   }
   else
   {     /*Another gadget was toggled*/
      strcpy(SearchForSInfo.Buffer,parameters.Search);
      strcpy(ReplaceWithSInfo.Buffer,parameters.Replace);
      SrchRplc.Flags = (parameters.rep)
            ? GADGHIMAGE+GADGIMAGE+SELECTED : GADGHIMAGE+GADGIMAGE;
      PartialWord.Flags = (parameters.partial)
            ? GADGHIMAGE+GADGIMAGE : GADGHIMAGE+GADGIMAGE+SELECTED;
      CaseSensitive.Flags = (parameters.cse) ? GADGHIMAGE+GADGIMAGE+SELECTED
            : GADGHIMAGE+GADGIMAGE;
   }
      
   CloseWindow(SearchWdw);
   return(status);
}

MonitorButtons() /*Monitor the IDCMP port*/
{
   ULONG Class;
   struct Gadget *gadg;
   struct IntuiMessage *mesg;
   
   for(;;)
   {
      Wait(1<<SearchWdw->UserPort->mp_SigBit);
      while((mesg=(struct IntuiMessage *)GetMsg(SearchWdw->UserPort))!=NULL)
      {
         Class=mesg->Class;   /*Get the information*/
         gadg=mesg->IAddress; 
         ReplyMsg(mesg);      /*Reply to the message*/
         switch(Class)
         {
            case CLOSEWINDOW: /*Close gadget == CANCEL*/
               return(FALSE);
            case GADGETUP:
               switch(gadg->GadgetID)
               {
                  case 8:  /*Cancel*/
                     return(FALSE);
                  case 7:  /*Wait*/
                     return(MAYBE);
                  case 6:  /*OK*/
                     return(TRUE);
                  case 1:
                     ActivateGadget(&ReplaceWith,SearchWdw,NULL);
                        /*Activate the Replace with... string gadget when*/
                        /*the user presses RETURN in the Search for...*/
                        /*gadget*/
                     return(NONONO); /*Don't alter a flag :-) */
               }
         }
      }
   }
}


extern struct LineItem *SearchText(Item,Pos,string,scase,partial)
      /*Search an outline for a particular string of characters*/
struct LineItem *Item; /*Item to start searching on*/
USHORT *Pos;           /*Position in that item to start on*/
char *string;          /*Search string*/
BYTE scase,partial;    /*scase  - TRUE if case matters, FALSE otherwise*/
                       /*partial-TRUE if it may be a part of a word*/
{
   int c,found,start,thestart;
   struct LineItem *cur,*theitem;
   BYTE status=FALSE;
   char chr,fchr;
   
   if(!scase) /*If case sensitive, convert the string to all uppercase*/
      for(c=0;c<strlen(string);c++)
         string[c]=toupper(string[c]);
         
   if(*Pos >= strlen(Item->Text)) /*If at the end of the line*/
   {
      start=0;  /*Start of next line*/
      Item=(struct LineItem *)Item->NextItem;
   }
   else
      start=*Pos;  /*Else, start at cursor position*/
      
   for(cur=(struct LineItem *)Item;cur != NULL && !status;/*Search until end*/
         cur=(struct LineItem *)cur->NextItem) /*or text is found*/
      for(c=start;c<strlen(cur->Text) && !status ;++c)
      {        /*Loop that searches each line:  */
         start=0;
                  
         if((partial) || ( (!partial) && ((c==0) || (cur->Text[c-1]==' ') )))
               /*If partial words are OK, or if not, if the character*/
               /*currently being checked is the first letter in a word*/
         {
            if(!scase)  /*If case is important*/
               chr=toupper(cur->Text[c]); /*Switch to uppercase (see above)*/
            else
               chr=cur->Text[c];

            if(string[0]==chr) /*If first character matches...*/
            {
               status=TRUE;
               theitem=(struct LineItem *)cur;
               thestart=c;
               for(found=1;found<strlen(string) && status ;found++)
               {     /*see if the rest matches...*/
                  if(!scase)
                     fchr=toupper(cur->Text[c+found]);
                  else
                     fchr=cur->Text[c+found];
                     
                  if(fchr!=string[found])
                     status=FALSE;
               }                    /*If the word is a prefix of another word*/
               if(cur->Text[c+found] != ' ' && cur->Text[c+found]!= NULL &&
                        !partial)
                  status = FALSE;      /*return FALSE*/
            }
         }
      }
   if(status) /*If found...*/
   {
      *Pos=thestart;    /*Return the position of the start of the text*/
      return(theitem);  /*And the item that it is found in*/
   }                    /*(so that the cursor can be moved accordingly)*/
   else
      return(NULL);     /*Otherwise, nothing*/
}

DoSearch(again,arexx)  /*Main entry point for 'Search/Replace' and 'Next'*/
BYTE again,arexx;      /*Again:  TRUE if 'Next', FALSE if 'Search/Replace'*/
{
   char Buffer[8],reslt[160],preservation[80];
   int status;
   UBYTE TempY;
   struct LineItem *tempitem,*result;
   struct LineItem *firstitem=(struct LineItem *)CurrentItem;
   
   USHORT Pos=(again && again != 100) ? CurX-MinX(CurrentItem)+1 :
          CurX-MinX(CurrentItem);
   
   
   status = (again) ? TRUE : GetSRParameters();
         /*If 'Next', search no matter what.  Otherwise, depends on user*/
   CancelInvs();  /*Cancel text highlighting*/
   if(ErrorInTitle)     /*Cancel any errors in the title bar*/
      TitleErrorCancel();
   
   
   if(status)     /*If it's OK to search*/
   {
      strcpy(preservation,parameters.Search);   /*Store the search string*/
            /*so if SearchText turns it to all caps, we'll still have the*/
            /*original*/
            
      result=(struct LineItem *) /*Search the text*/
            SearchText(CurrentItem,&Pos,parameters.Search,parameters.cse,
            parameters.partial);
   
      if(result!=NULL)  /*If found...*/
      {
         /*Place the cursor at the start of the word*/
         if(result!=FirstScrnItem || result!=firstitem)
         {
            FirstScrnItem=CurrentItem=(struct LineItem *)result;
            PrintItemList(CurrentItem,1);
         }
         PlotCursor(MinX(CurrentItem)+Pos,1);
         if(parameters.rep) /*If a search and replace*/
         {                  /*Replace!!!!*/
            strcpy(reslt,&(CurrentItem->Text[Pos+strlen(parameters.Search)]));
            strins(reslt,parameters.Replace);
            CurrentItem->Text[Pos]=NULL;
            strins(reslt,CurrentItem->Text);
                       
               /*Break the line apart if necessary*/
            tempitem=(struct LineItem *)BreakLineApart(CurrentItem,
                  CurrentItem->NextItem,reslt);
            
            PlotCursor(1,CurY);
            Buffer[0]=CSI;
            Buffer[1]=0x4b;
            WriteConsole(Buffer,2);
            TempY=CurY;
            if(tempitem==CurrentItem)
               PrintItem(CurrentItem);
            else
               PrintItemList(CurrentItem,CurY);
            PlotCursor(MinX(CurrentItem)+Pos,TempY);
            CheckModified();  /*Text has been modified*/
         }
         strcpy(parameters.Search,preservation);
         return(TRUE);
      }
      else  /*If it wasn't found*/
      {
         strcpy(parameters.Search,preservation);
         if(!arexx)  /*If this wasn't an ARexx command*/
            TitleError("Wasn't found!!!");
         return(FALSE);
      }
   }
}

void ModifyParams(search,replace,case_s,partial,s_repl)
char *search,*replace;
BYTE case_s,partial,s_repl;
{
   if(search[0]!=NULL)
      strcpy(parameters.Search,search);
   if(replace[0]!=NULL)
      strcpy(parameters.Replace,replace);
   if(case_s!=100)
      parameters.cse=case_s;
   if(partial!=100)
      parameters.partial=partial;
   if(s_repl!=100)
      parameters.rep=s_repl;
}

void ReplaceAll(verify) /*Search/replace entire document at once*/
BYTE verify;
{
   BYTE stat;
   
   if(verify)
   {
      ModifyParams("","",100,100,FALSE);
      while(DoSearch(TRUE,TRUE)) /*Search for text*/
      {
         if(stat=AskChange()) /*Ask user what to do*/
         {
            if(stat==TRUE) /*Replace*/
            {
               ModifyParams("","",100,100,TRUE);
               DoSearch(100,TRUE);
               ModifyParams("","",100,100,FALSE);
            } /*Else goto next*/
         }
         else
            return;  /*Else cancel*/
      }
      TitleError("No more found");
   }
   else   /*Do all without verification*/
   {
      ModifyParams("","",100,100,TRUE);
      while(DoSearch(TRUE,TRUE));
   }
}

BYTE AskChange() /*Ask user if he wants to do replace*/
{
   struct Window *ReplAllWdw;
   struct IntuiMessage *mesg;
   struct Gadget *gadg;
   
   NewWindowStructure2.Screen=(struct Screen *)Screen; /*'Liner screen*/
   if((ReplAllWdw=(struct Window *)OpenWindow(&NewWindowStructure2))==NULL)
      return(FALSE); /*Open the window*/
      
   PrintIText(ReplAllWdw->RPort,&IntuiTextList2,0,0);
   Wait(1<<ReplAllWdw->UserPort->mp_SigBit); /*Wait for gadget press*/

   if((mesg=(struct IntuiMessage *)GetMsg(ReplAllWdw->UserPort))==NULL)
   {
      CloseWindow(ReplAllWdw);
      return(FALSE); /*Get the message*/
   }
   
   gadg=(struct Gadget *)mesg->IAddress;/*Get the gadget structure's addr*/
   
   ReplyMsg(mesg); /*Reply to it*/
   
   
   CloseWindow(ReplAllWdw); /*Close the window*/
   return(gadg->GadgetID); /*Return the gadget ID*/
}

/*End of Search.c*/
