/*****************************************************************************
#   Copyright (C) 1994-2008 by David Gordon.
#   All rights reserved.                           
#                                                                           
#   This software is part of a beta-test version of the Consed/Autofinish
#   package.  It should not be redistributed or
#   used for any commercial purpose, including commercially funded
#   sequencing, without written permission from the author and the
#   University of Washington.
#   
#   This software is provided ``AS IS'' and any express or implied
#   warranties, including, but not limited to, the implied warranties of
#   merchantability and fitness for a particular purpose, are disclaimed.
#   In no event shall the authors or the University of Washington be
#   liable for any direct, indirect, incidental, special, exemplary, or
#   consequential damages (including, but not limited to, procurement of
#   substitute goods or services; loss of use, data, or profits; or
#   business interruption) however caused and on any theory of liability,
#   whether in contract, strict liability, or tort (including negligence
#   or otherwise) arising in any way out of the use of this software, even
#   if advised of the possibility of such damage.
#
#   Building Consed from source is error prone and not simple which is
#   why I provide executables.  Due to time limitations I cannot
#   provide any assistance in building Consed.  Even if you do not
#   modify the source, you may introduce errors due to using a
#   different version of the compiler, a different version of motif,
#   different versions of other libraries than I used, etc.  For this
#   reason, if you discover Consed bugs, I can only offer help with
#   those bugs if you first reproduce those bugs with an executable
#   provided by me--not an executable you have built.
# 
#   Modifying Consed is also difficult.  Although Consed is modular,
#   some modules are used by many other modules.  Thus making a change
#   in one place can have unforeseen effects on many other features.
#   It may takes months for you to notice these other side-effects
#   which may not seen connected at all.  It is not feasable for me to
#   provide help with modifying Consed sources because of the
#   potentially huge amount of time involved.
#
#*****************************************************************************/
//
// gui_search_for_string.cpp
//
// implementation for GuiSearchForString class
//
// Used to put up a dialog box with query string, get a user response,
// and return a list of matches
//
// David Gordon, July 1995
//




#include    <Xm/Form.h>
#include    <Xm/Label.h>
#include    <Xm/Text.h>
#include    <stdio.h>
#include    <Xm/PushB.h>
#include    "gui_search_for_string.h"
#include    "search_for_string.h"
#include    "guiapp.h"
#include    "gui_get_selection.h"
#include    <iostream.h>
#include    <Xm/ToggleB.h>
#include    <Xm/RowColumn.h>
#include    "searchMethods.h"
#include    <Xm/MainW.h>
#include    "handleWindowManagerDelete.h"
#include    "hp_exception_kludge.h"
#include    "bIsNumericMaybeWithWhitespace.h"
#include    "popupErrorMessage.h"
#include    "consedParameters.h"
#include    "searchMethods.h"
#include    "consed.h"
#include    "rwcregexp.h"
#include    "soGetErrno.h"


void cbSearch( Widget widCallback, XtPointer client_data, 
                    XtPointer call_data ) {

   XmAnyCallbackStruct* pXmAnyCallbackStruct = 
     (XmAnyCallbackStruct*) call_data;

   GuiSearchForString* pGuiSearchForString = (GuiSearchForString *) client_data;
   TRY_CATCH_WRAPPER(
                     pGuiSearchForString->guiDoSearch( widCallback, 
                                                       pXmAnyCallbackStruct );
                     );
}



void cbClearQueryString( Widget widCallback, XtPointer client_data, 
                    XtPointer call_data ) {

   XmAnyCallbackStruct* pXmAnyCallbackStruct = 
     (XmAnyCallbackStruct*) call_data;

   GuiSearchForString* pGuiSearchForString = (GuiSearchForString *) client_data;
   TRY_CATCH_WRAPPER(
                     pGuiSearchForString->guiClearQueryString( );
                     );
}



void cbCancelSearch( Widget widCallback, XtPointer client_data, 
                    XtPointer call_data ) {

   GuiSearchForString* pGuiSearchForString = (GuiSearchForString *) client_data;
   TRY_CATCH_WRAPPER(
                     delete pGuiSearchForString;
                     );
}


void    cbChangeContigsVsReads( Widget wid, XtPointer client_data, 
                             XtPointer call_data ) {

   GuiSearchForString* pGuiSearchForString = (GuiSearchForString*) client_data;
   TRY_CATCH_WRAPPER(
                     pGuiSearchForString->changeContigsVsReads();
                     );
}


void    cbChangeSearchMethod( Widget wid, XtPointer client_data, 
                             XtPointer call_data ) {

   GuiSearchForString* pGuiSearchForString = (GuiSearchForString*) client_data;

   TRY_CATCH_WRAPPER(
                     pGuiSearchForString->changeSearchMethod( wid, call_data );
                     );

}


void    GuiSearchForString :: changeSearchMethod( const Widget wid, 
                                                    const XtPointer& call_data ) {

   XmToggleButtonCallbackStruct* pToggleButtonCallbackStruct = 
     (XmToggleButtonCallbackStruct*) call_data;


   if ( pToggleButtonCallbackStruct -> set ) {
      if (wid == widSearchMethodExact_ ) 
        nSearchMethod_ = nExact;
      else if (wid == widSearchMethodSmithWaterman_ )
        nSearchMethod_ = nInexact;
   }
}




void    GuiSearchForString :: guiDoSearch( Widget widCallback, 
                            XmAnyCallbackStruct* pXmAnyCallbackStruct )  {

   char *szQueryString = XmTextGetString( widQueryString_ );
   RWCString soQueryString = szQueryString;
   XtFree( szQueryString );

   if (soQueryString.length() == 0 ) {
      GuiApp::popupErrorMessage( "You must enter a query string" );
      return;
   }


   char* szPerCentMismatch = XmTextGetString( widPerCentMismatch_ );

   int nPerCentMismatch;
   if ( !bIsNumericMaybeWithWhitespace( szPerCentMismatch, 
                                        nPerCentMismatch ) ) {
      popupErrorMessage( "The per cent mismatch must be between 0 and 30" );
      return;
   }

   if ( !
        ( 0 <= nPerCentMismatch &&
          nPerCentMismatch <= 30 ) ) {
      popupErrorMessage( "The per cent mismatch must be between 0 and 30" );
      return;
   }

   // check that singlets file exists

   FileName filSingletsFile;
   
   if ( !bJustContigsNotReads_ ) {

      filSingletsFile = XmTextGetString( widSingletsFile_ );

      if ( !filSingletsFile.isNull() ) {
         // check Consed can open this file

         FILE* pSingletsFile = fopen( filSingletsFile.data(), "r" );
         if ( !pSingletsFile ) {
            RWCString soErrorMessage = "could not open ";
            soErrorMessage += filSingletsFile;
            soErrorMessage += " for read. ";
            soErrorMessage += soGetErrno();
            popupErrorMessage( soErrorMessage );
            return;
         }

         fclose( pSingletsFile );
      }

   }


   popupOutputWindowAndDoSearch( soQueryString, 
                                 nSearchMethod_, 
                                 bJustContigsNotReads_,
                                 nPerCentMismatch,
                                 filSingletsFile );
}




void    GuiSearchForString :: popupAskForSearchString() {

   Arg              aArg[100];
   int              nArgs;
   XmStringTable    xmStringList;
   int              n;



   widPopupShell_ = XtVaCreatePopupShell("Search For String",
                                  topLevelShellWidgetClass,
                                  GuiApp::pGetGuiApp()->widGetTopLevel(),
                                  XmNdeleteResponse, XmDO_NOTHING,
                                  NULL );
   
   handleWindowManagerDelete( widPopupShell_ );

   // the immediate child of the application shell is a
   // main window
   Widget widMainWin = 
     XtVaCreateManagedWidget("mainwin", 
                             xmMainWindowWidgetClass, widPopupShell_,
                             XmNancestorSensitive, True,  
                             NULL );

   //
   // create the form widget
   //
   nArgs = 0;
   XtSetArg(aArg[nArgs],XmNshadowThickness,0); nArgs++;
   XtSetArg(aArg[nArgs],XmNborderWidth,0); nArgs++;
   Widget widForm = XmCreateForm(widMainWin,
                           "form",
                           aArg,
                           nArgs);
   XtManageChild(widForm);



   Widget   widLabel = XtVaCreateManagedWidget("Query string:  ",
                   xmLabelWidgetClass,
                   widForm,
                   XmNtopAttachment, XmATTACH_FORM,
                   XmNtopOffset, 20,
                   XmNleftAttachment, XmATTACH_FORM,
                   XmNleftOffset, 20,
                   NULL );


   nArgs = 0;
   XtSetArg( aArg[ nArgs ], XmNleftAttachment, XmATTACH_FORM ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNrightAttachment, XmATTACH_FORM); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNleftOffset, 20); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNrightOffset, 20); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNtopAttachment, XmATTACH_WIDGET); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNtopWidget, widLabel ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNeditMode, XmSINGLE_LINE_EDIT ); ++nArgs;
   widQueryString_ = XtCreateManagedWidget( "QueryString", xmTextWidgetClass,
                                           widForm, 
                                                aArg, nArgs );

   XtAddCallback( widQueryString_,
                 XmNactivateCallback,
                 cbSearch,
                 this );


   widClearButton_ = XtVaCreateManagedWidget( "Clear",
        xmPushButtonWidgetClass,
        widForm,
       XmNtopAttachment, XmATTACH_WIDGET,
       XmNtopWidget, widQueryString_,
       XmNtopOffset, 20,
       XmNleftAttachment, XmATTACH_FORM,
       XmNleftOffset, 20,
       XmNrightAttachment, XmATTACH_FORM,
       XmNrightOffset, 20,
       XmNtraversalOn, False,
       NULL );                                                 

   
   XtAddCallback( widClearButton_,
                 XmNactivateCallback,
                 cbClearQueryString,
                 this );
                                              




   // search all reads vs search just contig



   nArgs = 0;
   XtSetArg( aArg[ nArgs ], XmNleftAttachment, XmATTACH_FORM ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNrightAttachment, XmATTACH_FORM); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNleftOffset, 20); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNrightOffset, 20); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNtopAttachment, XmATTACH_WIDGET); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNtopWidget, widClearButton_ ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNtopOffset, 40 ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNbottomOffset, 40 ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNmarginWidth, 0 ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNtraversalOn, False ); ++nArgs; 
   Widget   widContigsVsReadsRadioBox = XmCreateRadioBox( widForm,
                                           "radio_box",
                                           aArg,
                                           nArgs );

   XtManageChild( widContigsVsReadsRadioBox );

   bJustContigsNotReads_ = true;

   widSearchJustContigs_ = XtVaCreateManagedWidget("Search Just Contigs",
                                               xmToggleButtonWidgetClass,
                                               widContigsVsReadsRadioBox,
                                               XmNset,
                                               True,
                                               NULL );

   XtAddCallback( widSearchJustContigs_, XmNvalueChangedCallback, 
                 cbChangeContigsVsReads, 
                 this );


   widSearchJustReads_ = XtVaCreateManagedWidget("Search Just Reads",
                                               xmToggleButtonWidgetClass,
                                               widContigsVsReadsRadioBox,
                                                       NULL );

// Don't have this callback since the one above for widSearchJustContigs_
// will already call cbChangeContigsVsReads
//    XtAddCallback( widSearchReadsAndContigs_, XmNvalueChangedCallback, 
//                  cbChangeContigsVsReads, 
//                  this );



   // exact/ Smith-Waterman search

   nArgs = 0;
   XtSetArg( aArg[ nArgs ], XmNleftAttachment, XmATTACH_FORM ); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNrightAttachment, XmATTACH_FORM); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNleftOffset, 20); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNrightOffset, 20); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNtopAttachment, XmATTACH_WIDGET); ++nArgs;
   XtSetArg( aArg[ nArgs ], XmNtopWidget, widContigsVsReadsRadioBox); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNtopOffset, 40 ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNbottomOffset, 40 ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNmarginWidth, 0 ); ++nArgs; 
   XtSetArg( aArg[ nArgs ], XmNtraversalOn, False ); ++nArgs; 
   Widget   widRadioBox = XmCreateRadioBox( widForm,
                                           "radio_box",
                                           aArg,
                                           nArgs );

   XtManageChild( widRadioBox );

   nSearchMethod_ = nExact;

   widSearchMethodExact_ = XtVaCreateManagedWidget("Exact",
                                               xmToggleButtonWidgetClass,
                                               widRadioBox,
                                               XmNset,
                                               True,
                                               NULL );

   XtAddCallback( widSearchMethodExact_, XmNvalueChangedCallback, 
                 cbChangeSearchMethod, 
                 this );


   widSearchMethodSmithWaterman_ = XtVaCreateManagedWidget("Approximate",
                                               xmToggleButtonWidgetClass,
                                               widRadioBox,
                                               NULL );

   XtAddCallback( widSearchMethodSmithWaterman_, XmNvalueChangedCallback, 
                 cbChangeSearchMethod, 
                 this );



   Widget widPerCentMismatchForm =
      XtVaCreateManagedWidget( "Per Cent Mismatch Form",
                               xmFormWidgetClass,
                               widForm,
                               XmNshadowThickness, 0,
                               XmNleftAttachment, XmATTACH_FORM,    
                               XmNrightAttachment, XmATTACH_FORM,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, widRadioBox,
                               XmNtopOffset, 20,
                               NULL );


   Widget widPerCentMismatchLabel = 
      XtVaCreateManagedWidget( "Per Cent Mismatch: ",
                               xmLabelWidgetClass,
                               widPerCentMismatchForm,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNleftOffset, 20,
                               XmNtopAttachment, XmATTACH_FORM,
                               XmNbottomAttachment, XmATTACH_FORM,
                               NULL );

   RWCString soDefaultPerCentMismatch( (long) 
                   pCP->nInexactSearchForStringMaxPerCentMismatch_ );

   widPerCentMismatch_ = 
      XtVaCreateManagedWidget( "Per Cent Mismatch",
                               xmTextWidgetClass,
                               widPerCentMismatchForm,
                               XmNleftAttachment, XmATTACH_WIDGET,
                               XmNleftWidget, widPerCentMismatchLabel,
                               XmNrightAttachment, XmATTACH_FORM,
                               XmNrightOffset, 20,
                               XmNtopAttachment, XmATTACH_FORM,
                               XmNbottomAttachment, XmATTACH_FORM,
                               XmNeditMode, XmSINGLE_LINE_EDIT,
                               XmNcolumns, 3,
                               XmNvalue, soDefaultPerCentMismatch.data(),
                               NULL );


   XmString xmsSingletFile = XmStringCreateLtoR( "Singlets file to also search\n(leave blank to not search it):",
                                                 XmFONTLIST_DEFAULT_TAG );

   widSingletsFileLabel_ = 
      XtVaCreateManagedWidget( "singlets_label",
                               xmLabelWidgetClass,
                               widForm,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNleftOffset, 20,
                               XmNrightAttachment, XmATTACH_FORM,
                               XmNrightOffset, 20,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, widPerCentMismatchForm,
                               XmNlabelString, xmsSingletFile,
                               XmNalignment, XmALIGNMENT_BEGINNING,
                               XmNsensitive, False, // starting out just contigs
                               NULL );

   XmStringFree( xmsSingletFile );

   FileName filSingletsFile = ConsEd::pGetAssembly()->soGetAceFileName();
   // chop off everything starting with .fasta.screen.
   RWCRegexp regFasta( "\\.fasta\\.screen\\..*$" );
   filSingletsFile( regFasta ) = "";

   filSingletsFile += ".fasta.screen.singlets";

   widSingletsFile_ = 
      XtVaCreateManagedWidget( "singlets_file",
                               xmTextWidgetClass,
                               widForm,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNleftOffset, 20,
                               XmNrightAttachment, XmATTACH_FORM,
                               XmNrightOffset, 20,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, widSingletsFileLabel_,
                               XmNeditMode, XmSINGLE_LINE_EDIT,
                               XmNvalue, filSingletsFile.data(),
                               XmNsensitive, False, // starting out just contigs
                               NULL );

   Widget widConnectToTopWidget = widSingletsFile_;


   widOKButton_ = XtVaCreateManagedWidget( "OK",
       xmPushButtonWidgetClass,
       widForm,
       XmNtopAttachment, XmATTACH_WIDGET,
       XmNtopWidget, widConnectToTopWidget,
       XmNtopOffset, 20,

       XmNleftAttachment, XmATTACH_POSITION,
       XmNleftPosition,10 ,                                                
       XmNrightAttachment, XmATTACH_POSITION,
       XmNrightPosition,45 ,                                                

       XmNbottomAttachment, XmATTACH_FORM,
       XmNbottomOffset, 20,                                          
       XmNtraversalOn, False,
       NULL );                                                 

   
   XtAddCallback( widOKButton_,
                 XmNactivateCallback,
                 cbSearch,
                 this );

   widCancelButton_ = XtVaCreateManagedWidget( "Cancel",
        xmPushButtonWidgetClass,
        widForm,
       XmNtopAttachment, XmATTACH_WIDGET,
       XmNtopWidget, widConnectToTopWidget,
       XmNtopOffset, 20,

       XmNleftAttachment, XmATTACH_POSITION,
       XmNleftPosition,55 ,                                                
       XmNrightAttachment, XmATTACH_POSITION,
       XmNrightPosition,90 ,                                                

       XmNbottomAttachment, XmATTACH_FORM,
       XmNbottomOffset, 20,                                          
       XmNtraversalOn, False,
       NULL );                                                 

   
   XtAddCallback( widCancelButton_,
                 XmNactivateCallback,
                 cbCancelSearch,
                 this );


// pop it all up
// Note:  if you do this any earlier, the bottom of the dialog will be
// off the screen since it grows downward after being popped up.

   XtPopup( widPopupShell_, XtGrabNone );

   // make the query box initially have input focus
   XmProcessTraversal( widQueryString_, XmTRAVERSE_CURRENT );

}




void  GuiSearchForString :: guiClearQueryString( ) {
   XmTextSetString( widQueryString_, "" );
}



void GuiSearchForString :: raiseWindow() {

   XRaiseWindow(
                XtDisplay( widPopupShell_ ),
                XtWindow( widPopupShell_ )
                );
}


GuiSearchForString :: ~GuiSearchForString() { 
   
   ConsEd::pGetConsEd()->pGuiSearchForString_ = NULL;

   XtDestroyWidget( widPopupShell_ ); 
}


void GuiSearchForString :: changeContigsVsReads() { 
   bJustContigsNotReads_ = ! bJustContigsNotReads_; 


   if ( bJustContigsNotReads_ ) {
      XtVaSetValues( widSingletsFile_, XmNsensitive, False, NULL );
      XtVaSetValues( widSingletsFileLabel_, XmNsensitive, False, NULL );
   }
   else {
      XtVaSetValues( widSingletsFile_, XmNsensitive, True, NULL );
      XtVaSetValues( widSingletsFileLabel_, XmNsensitive, True, NULL );
   }
}