
/*  Find.c: the FindPanel and related functions
 *
 *  This file is part of Aileron, a WINGs email client. 
 *
 *  Copyright (c) 1999 - 2001  Nwanua Elumeze
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include "Aileron.h"

struct {
  WMWindow    *window;
  WMTextField *findt, *replacet;
  WMLabel     *replacel, *notfoundl;
  WMButton    *summaryb, *messageb, *ignoreb, *regexpb, *nextb;
  WMButton    *allb, *replaceb, *replFindb, *allselectb;
  unsigned    short found:1;
  unsigned    short newMessages:1;
  unsigned   short RESERVED:14;
} FindPanel;


enum {all, replace, replFind, prev, next} _findType;

void genericFind(int type);

char *getMessageData(MAILSTREAM *stream, long msgno)
{
  
  if(msgno < 1 || msgno > stream->nmsgs)
    return NULL;
    
  if(WMGetButtonSelected(FindPanel.summaryb)) { 

    time_t t;
    MESSAGECACHE *msgcache;
    char *line, buf[MAILTMPLEN];
    int i;

    msgcache = mail_elt(stream, msgno);
    if(!msgcache)
      return NULL;
    
    t = mail_longdate(msgcache);
    strftime(buf, 7, "%d %b", localtime(&t));
    line = wstrdup(buf);
    
    memset(buf, 0, MAILTMPLEN-1);
    mail_fetchfrom(buf, stream, msgno, (long)MAILTMPLEN-1);
    if ((i = strlen(buf)) > 0 ) {
      do --i; while(i>0 && buf[i] == ' ');
      buf[i+1] = 0;
      line = wstrappend(line, buf);
    }

    mail_fetchsubject(buf, stream, msgno, (long)MAILTMPLEN-1);
    return wstrappend(line, buf);

  } else {
    return wstrdup(mail_fetch_text(stream, msgno, NIL, NIL, FT_PEEK | FT_INTERNAL));
  }

} 

Bool
getRegularExpression(char *haystack, char *needle)
{
  if(!haystack || !needle)
    return 0;

printf("getRegularExpression\n");
  return 1;
}

Bool
strCaseStr(char *haystack, char *needle)
{
  char *h, *n;
  int i, len;

  if(!haystack || !needle)
    return 0;

  h = wstrdup(haystack);
  for(i=0, len=strlen(haystack); i<len; i++) 
    h[i] = tolower(h[i]); 
  
  n = wstrdup(needle);
  for(i=0, len=strlen(needle); i<len; i++) 
    n[i] = tolower(n[i]); 

  i = (Bool) strstr (h, n);
  wfree(n);
  wfree(h);
  return i;
}

static void
findTextInComposer(char *needle, Bool type)
{
  WMText *tPtr;
  static Bool prior = False;

  if(!Aileron.composer || !needle)
    return;

  if(!(tPtr = GetComposerMessageView(Aileron.composer)))
    return;

  if(type == replace || type == replFind) { 
    char *text = WMGetTextFieldText(FindPanel.replacet);

    if(strlen(text) > 0) 
      WMReplaceTextSelection(tPtr, text);
    else
      WMReplaceTextSelection(tPtr, NULL);

    wfree(text);

    if(type == replace) 
      return;
  }
  
  if(type == next || type == prev)
    prior = !(type == prev);

  FindPanel.found = WMFindInTextStream(tPtr, needle, 
    prior, !WMGetButtonSelected(FindPanel.ignoreb));

  if(!FindPanel.found) {  
    XBell(Aileron.display, 0);
    WMSetLabelText(FindPanel.notfoundl, "Not found");
    return;
  }

  WMSetLabelText(FindPanel.notfoundl, " ");

}

static void 
findMessageInMailBox(char *needle, Bool ignoreCase,
  Bool regExp, Bool type)
{
  WMListItem *item;
  int current, total, oldrow;
  Bool found=False, first=True;
  char *haystack;
  MAILSTREAM *stream;
  WMList *list = NULL;
  

  if(!Aileron.mbox)
    return;
  
  list = GetMailBoxSummaryView(Aileron.mbox);

  if(!(stream=GetMailBoxStream(Aileron.mbox)) || !list || !needle)
    return;

  if(type == replace || type == replFind)
    return;
  
  if((total = WMGetListNumberOfRows(list)) < 1)
    return;

  if(type == all) {
    current = 0;
  } else {
    current = oldrow = WMGetListSelectedItemRow(list);
  }

  if(current == WANotFound)
    current = (type == prev? total : 0);


  if(type != all) { 
    if(type == prev)
      current += (current>0?-1:1);
    else
      current += (current<total?1:-1);
  }

  do { 

    item = WMGetListItem(list, current);
    if(!item || !item->text) 
      break;
    
    haystack = getMessageData(stream, *(long *)(item->text));
    if(!haystack)
      break;

    found = (regExp ? getRegularExpression(haystack, needle)
      : (ignoreCase? strCaseStr(haystack, needle)
      : (Bool) strstr (haystack, needle)));

    wfree(haystack);

    if(found) {
      FindPanel.found = True;
      if(first) { 
        WMUnselectAllListItems(list);
        WMSetListPosition(list, current);
        first = False;
      } 

      WMSelectListItem(list, current);
      if(type != all)
        break;

    }

  } while((type == prev)? (current-->=0):(current++<total)); 


  if(!FindPanel.found) {  
    XBell(Aileron.display, 0);
    WMSetLabelText(FindPanel.notfoundl, "Not found");
  } else {
    WMSetLabelText(FindPanel.notfoundl, " ");
  }
}


void closePanel(WMWidget *self, void *client)
{
  WMUnmapWidget(FindPanel.window);

}



void buttonReplaceCB(WMWidget *w, void *client)
{
  findTextInComposer(Aileron.selectionText, replace);
}

void buttonReplaceAndFindCB(WMWidget *w, void *client)
{
  findTextInComposer(Aileron.selectionText, replFind);
}

void buttonFindPreviousCB(WMWidget *w, void *client)
{
  FindPrevious();
}


void buttonFindNextCB(WMWidget *w, void *client)
{
  FindNext();
}

void buttonFindAllCB(WMWidget *w, void *client)
{
  genericFind(all);
}

void buttonFindAndFocusCB(WMWidget *w, void *client)
{
  buttonFindAllCB(w, client);
  if(FindPanel.found) 
    FocusMailBox(Aileron.mbox, True);  
}


static void
handleKeyPress(XEvent *event, void *null)
{
  KeySym ksym;
  
  XLookupString(&event->xkey, NULL, 0, &ksym, NULL);
  
  if(ksym == XK_Return)
    WMPerformButtonClick(FindPanel.nextb);
}

static void
runFindPanel(void)
{
  WMLabel *l;
  WMButton *b;
  WMFrame *f;

  FindPanel.window = WMCreateWindowWithStyle(Aileron.screen, "Find", 
    WMTitledWindowMask|WMClosableWindowMask);
  WMSetWindowTitle(FindPanel.window, "Aileron: Find Panel");
  WMResizeWidget(FindPanel.window, 400, 165);
  WMCreateEventHandler(WMWidgetView(FindPanel.window), KeyPressMask,
    handleKeyPress, NULL);

  
  l = NewLabel(FindPanel.window, "Find:", 57, 10, 34, 20);
  FindPanel.findt = 
    NewTextField(FindPanel.window, Aileron.selectionText, 91, 10, 300, 20);
  WMCreateEventHandler(WMWidgetView(FindPanel.findt), KeyPressMask,
    handleKeyPress, NULL);

  FindPanel.replacel = 
    NewLabel(FindPanel.window, "Replace with:", 10, 35, 82, 20);
  //WMSetLabelTextColor(FindPanel.replacel, WMDarkGrayColor(Aileron.screen));
  FindPanel.replacet = 
    NewTextField(FindPanel.window, NULL, 91, 35, 300, 20);
  WMCreateEventHandler(WMWidgetView(FindPanel.replacet), KeyPressMask,
    handleKeyPress, NULL);

  FindPanel.notfoundl = 
    NewLabel(FindPanel.window, " ", 10, 85, 82, 20);
  WMSetLabelTextColor(FindPanel.notfoundl, WMDarkGrayColor(Aileron.screen));

  f =  WMCreateFrame(FindPanel.window);
  WMSetFrameRelief(f, WRGroove); 
  WMMoveWidget(f, 91, 60);
  WMResizeWidget(f, 130, 60);
  WMSetFrameTitle(f, "Find Scope");

  FindPanel.summaryb = WMCreateRadioButton(f);
  WMSetButtonText(FindPanel.summaryb, "Summaries");
  WMMoveWidget(FindPanel.summaryb, 15, 15);

  FindPanel.messageb = WMCreateRadioButton(f);
  WMSetButtonText(FindPanel.messageb, "Messages");
  WMMoveWidget(FindPanel.messageb, 15, 35);

  WMGroupButtons(FindPanel.summaryb, FindPanel.messageb);
  /* change to check if summary or message box was clicked in - Nwanua */
  WMPerformButtonClick(FindPanel.summaryb);
  WMMapSubwidgets(f);

  f =  WMCreateFrame(FindPanel.window);
  WMSetFrameRelief(f, WRGroove); 
  WMMoveWidget(f, 231, 60);
  WMResizeWidget(f, 160, 60);
  WMSetFrameTitle(f, "Find Options");

  FindPanel.ignoreb = WMCreateSwitchButton(f);
  WMSetButtonText(FindPanel.ignoreb, "Ignore Case");
  WMMoveWidget(FindPanel.ignoreb, 15, 15);

  FindPanel.regexpb = WMCreateSwitchButton(f);
  WMSetButtonText(FindPanel.regexpb, "Regular Expression");
  WMMoveWidget(FindPanel.regexpb, 15, 35);
  WMResizeWidget(FindPanel.regexpb, 140, 20);
  WMSetButtonEnabled(FindPanel.regexpb, False);

  WMMapSubwidgets(f);
  
  FindPanel.allb = WMCreateCommandButton(FindPanel.window);
  WMSetButtonText(FindPanel.allb, "Find All");
  WMSetButtonAction(FindPanel.allb, buttonFindAllCB, NULL);
  WMResizeWidget(FindPanel.allb, 60, 25);
  WMMoveWidget(FindPanel.allb, 10, 130);


  FindPanel.replaceb = WMCreateCommandButton(FindPanel.window);
  WMSetButtonText(FindPanel.replaceb, "Replace");
  WMResizeWidget(FindPanel.replaceb, 60, 25);
  WMMoveWidget(FindPanel.replaceb, 75, 130);
  WMSetButtonAction(FindPanel.replaceb, buttonReplaceCB, NULL);

  FindPanel.replFindb = WMCreateCommandButton(FindPanel.window);
  WMSetButtonText(FindPanel.replFindb, "Replace & Find");
  WMResizeWidget(FindPanel.replFindb, 105, 25);
  WMMoveWidget(FindPanel.replFindb, 140, 130);
  WMSetButtonAction(FindPanel.replFindb, buttonReplaceAndFindCB, NULL);

  FindPanel.allselectb = WMCreateCommandButton(FindPanel.window);
  WMSetButtonText(FindPanel.allselectb, "Find All & Focus");
  WMResizeWidget(FindPanel.allselectb, 170, 25);
  WMMoveWidget(FindPanel.allselectb, 75, 130);
  WMSetButtonAction(FindPanel.allselectb, buttonFindAndFocusCB, NULL);

  b = WMCreateCommandButton(FindPanel.window);
  WMSetButtonText(b, "Previous");
  WMResizeWidget(b, 65, 25);
  WMMoveWidget(b, 250, 130);
  WMSetButtonAction(b, buttonFindPreviousCB, NULL);

  b = FindPanel.nextb = WMCreateCommandButton(FindPanel.window);
  WMSetButtonText(b, "Next");
  WMSetButtonAction(b, buttonFindNextCB, NULL);
  WMResizeWidget(b, 70, 25);
  WMMoveWidget(b, 320, 130);
  WMSetButtonImageDefault(b);
  WMSetButtonImagePosition(b, WIPRight);

  WMSetWindowCloseAction(FindPanel.window, closePanel, NULL);


  WMRealizeWidget(FindPanel.window);
  WMMapSubwidgets(FindPanel.window);
  WMAppAddWindow(Aileron.appContext, WMWidgetXID(FindPanel.window));

  WMHashInsert(Aileron.windowTable, "_FIND_PANEL_", &FindPanel);
  FindPanel.newMessages = False;
  Aileron.findCreated = True;
  WMUnmapWidget(FindPanel.allselectb);

}


void RunFindPanel(void)
{
  if(Aileron.findCreated) {
    XRaiseWindow(Aileron.display, WMWidgetXID(FindPanel.window));
    ChangeFindPanelForContext();
    WMMapWidget(FindPanel.window);
    return;
  }

  runFindPanel();
  ChangeFindPanelForContext();
  WMMapWidget(FindPanel.window);
  
}

void genericFind(int type)
{

  FindPanel.found = False;
  if(!Aileron.findCreated) {
    printf("do the simple case\n");
    if(!Aileron.selectionText) { 
      XBell(Aileron.display, 0);
      return;
    }

    return;
  }

  if(Aileron.selectionText)  
    wfree(Aileron.selectionText);

  Aileron.selectionText = WMGetTextFieldText(FindPanel.findt);
  if(strlen(Aileron.selectionText) < 1) { 
    XBell(Aileron.display, 0);
    return;
  }
  

  if(Aileron.cORm && Aileron.mbox 
    && (type != replace && type != replFind)) { 

    findMessageInMailBox(Aileron.selectionText, 
      WMGetButtonSelected(FindPanel.ignoreb), 
      WMGetButtonSelected(FindPanel.regexpb), type);

  } else if(!Aileron.cORm && Aileron.composer
    && (type != all)) {
      findTextInComposer(Aileron.selectionText, type);
  }

}

 


void FindPrevious(void)
{
  genericFind(prev);
}

void FindNext(void)
{
  genericFind(next);
}



void ChangeFindPanelForContext(void)
{
  WMWindow *win = NULL;

  if(!Aileron.findCreated)
    return;

  if(Aileron.cORm && Aileron.mbox) { 
    win = GetMailBoxWindow(Aileron.mbox);
    WMSetTextFieldEditable(FindPanel.replacet, False);
    WMSetLabelTextColor(FindPanel.replacel, 
      WMDarkGrayColor(Aileron.screen));
    WMSetButtonEnabled(FindPanel.allb, True);
    WMSetButtonEnabled(FindPanel.replaceb, False);
    WMSetButtonEnabled(FindPanel.replFindb, False);
    WMSetButtonEnabled(FindPanel.regexpb, False);
    WMSetButtonEnabled(FindPanel.summaryb, True);
    WMSetButtonEnabled(FindPanel.messageb, True);
    WMMapWidget(FindPanel.allselectb);
    WMUnmapWidget(FindPanel.replaceb);
    WMUnmapWidget(FindPanel.replFindb);

  } else if(!Aileron.cORm && Aileron.composer) {
    win = GetComposerWindow(Aileron.composer);
    WMSetTextFieldEditable(FindPanel.replacet, True);
    WMSetLabelTextColor(FindPanel.replacel, 
      WMBlackColor(Aileron.screen));
    WMSetButtonEnabled(FindPanel.allb, False);
    WMSetButtonEnabled(FindPanel.replaceb, True);
    WMSetButtonEnabled(FindPanel.replFindb, True);
    WMSetButtonEnabled(FindPanel.regexpb, False);
    WMSetButtonEnabled(FindPanel.summaryb, False);
    WMSetButtonEnabled(FindPanel.messageb, False);
    WMUnmapWidget(FindPanel.allselectb);
    WMMapWidget(FindPanel.replaceb);
    WMMapWidget(FindPanel.replFindb);

  }

  if(win) 
    WMChangePanelOwner(FindPanel.window, win);

}
    
