/*********************************
*  SEARCH  01/02/91
*  Source file for STV
*  © Copyright 1990 Timm Martin
*  All Rights Reserved Worldwide
**********************************/

#include <ctype.h>
#include <exec/types.h>
#include <functions.h>
#include <intuition/intuition.h>
#include <string.h>
#include "func.h"
#include "main.h"

/********************
*  SEARCH REQUESTER
*********************/

#define HOFFSET 16
#define VOFFSET  8
#define TOFFSET  8

struct IntuiText search_text =
{
  /* UBYTE              FrontPen  */ RED,
  /* UBYTE              BackPen   */ BLUE,
  /* UBYTE              DrawMode  */ JAM1,
  /* SHORT              LeftEdge  */ HOFFSET,
  /* SHORT              TopEdge   */ VOFFSET,
  /* struct TextAttr *  ITextFont */ &text_attr,
  /* UBYTE *            IText     */ (STRPTR)"Search for:",
  /* struct IntuiText * NextText  */ NULL,
};

#define INPUT_LENGTH 21
UBYTE input_string[INPUT_LENGTH];
UBYTE input_undo  [INPUT_LENGTH];

struct StringInfo input_info =
{
  /* UBYTE * Buffer     */ input_string,
  /* UBYTE * UndoBuffer */ input_undo,
  /* SHORT   BufferPos  */ 0,
  /* SHORT   MaxChars   */ INPUT_LENGTH,
  /* SHORT   DispPos    */ 0,
};

struct Gadget input_gadget =
{
  /* struct Gadget *    NextGadget    */ NULL,
  /* SHORT              LeftEdge      */ HOFFSET,
  /* SHORT              TopEdge       */ LATER,
  /* SHORT              Width         */ LATER,
  /* SHORT              Height        */ LATER,
  /* USHORT             Flags         */ GADGHCOMP,
  /* USHORT             Activation    */ RELVERIFY,
  /* USHORT             GadgetType    */ REQGADGET | STRGADGET,
  /* APTR               GadgetRender  */ NULL,
  /* APTR               SelectRender  */ NULL,
  /* struct IntuiText * GadgetText    */ NULL,
  /* LONG               MutualExclude */ NULL,
  /* APTR               SpecialInfo   */ (APTR)&input_info,
  /* USHORT             GadgetID      */ 1,
  /* APTR               UserData      */ NULL,
};

struct Requester search_req =
{
  /* Requester *        OlderRequest */ NULL,
  /* SHORT              LeftEdge     */ LATER,
  /* SHORT              TopEdge      */ LATER,
  /* SHORT              Width        */ LATER,
  /* SHORT              Height       */ LATER,
  /* SHORT              RelLeft      */ 0,
  /* SHORT              RelTop       */ 0,
  /* struct Gadget *    ReqGadget    */ &input_gadget,
  /* struct Border *    ReqBorder    */ NULL,
  /* struct IntuiText * ReqText      */ &search_text,
  /* USHORT             Flags        */ NULL,
  /* UBYTE              BackFill     */ BLUE,
  /* struct Layer *     ReqLayer     */ NULL,
};

/* where to begin the search */
search_line = 0;

/**********
*  SEARCH
***********/

/*
This procedure asks the user for a string to search and tries to find it.
*/

void search( void )
{
  BOOL finished;
  int i;
  struct IntuiMessage *imessage;

  input_gadget.TopEdge = VOFFSET + stats.Baseline + TOFFSET;
  input_gadget.Width   = INPUT_LENGTH * stats.TextWidth;
  input_gadget.Height  = stats.TextHeight;

  /* calculate size of search requester */
  search_req.Width  = input_gadget.Width + 2 * HOFFSET;
  search_req.Height = input_gadget.TopEdge + input_gadget.Height + VOFFSET;

  /* center the search requester in the window */
  search_req.LeftEdge = (win->Width  - search_req.Width ) >> 1;
  search_req.TopEdge  = (win->Height - search_req.Height) >> 1;

  /* if opened the search requester OK */
  if (Request( &search_req, win ))
  {
    /* put cursor in gadget */
    for (i = 0; i < 2000 && !(input_gadget.Flags & SELECTED); i++)
      ActivateGadget( &input_gadget, win, &search_req );

    finished = NO;
    while (!finished)
    {
      WAIT_FOR_INPUT;
      /* only check for one message--the next message will be a REFRESHWINDOW
       * which needs to be handled by the main loop
       */
      while (WINDOW_INPUT)
      {
        /* if pressed return, want to search */
        if (imessage->Class == GADGETUP)
          finished = YES;
        ReplyMsg( (struct Message *)imessage );
      }
    }

    /* remove requester from window */
    EndRequest( &search_req, win );

    /* if string is not blank */
    if (input_string[0])
    {
      search_line = 0;
      search_again();
    }
  }
}

/****************
*  SEARCH AGAIN
*****************/

/*
Given the specified search string, this procedure attempts to find that
string from the current search line.
*/

void search_again( void )
{
  char *end;        /* end of file */
  REG int i;        /* position in search string */
  int length;       /* length of search string */
  REG char *start;  /* position in text file */

  SET_POINTER;

  /* make sure still some file to search */
  if (search_line < current_file.Lines)
  {
    /* find length of search string */
    length = strlen( (char *)input_string );

    /* start at beginning of current search line and find end of file */
    for (start = current_file.Table[search_line],
         end = current_file.Buffer + current_file.FileSize - length;
         start < end; start++ )
    {
      /* go until end of search string or until no match */
      for (i = 0; tolower( input_string[i] ) == tolower( start[i] ) &&
           i < length; i++);
      /* If went all the way to end of string, must've matched.  Added
       * search_line check just in case there are nulls in the file (e.g
       * binary file) and search_line has gone past bounds.
       */
      if (i == length && search_line < current_file.Lines)
      {
        /* start display at current search line */
        stats.Top = search_line;
        /* make sure it can fit */
        line_check();
        /* redisplay at new position & adjust prop gadget */
        text_display();
        modify_vprop();
        /* highlight search text */
        text_string( (int)(search_line - stats.Top),
                     (int)((long)start - (long)current_file.Table[search_line]),
                     length );
        /* begin searchin on next line */
        search_line++;
        CLEAR_POINTER;
        return;
      }
      /* else check if sitting on newline; if so, now moved to next line */
      else if (*start == '\0')
        search_line++;
    }
  }

  /* if made it here, never found desired string */
  DisplayBeep( win->WScreen );
  CLEAR_POINTER;
}
