/*****************************************************************************
#   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.
#
#*****************************************************************************/
//
// guiapp.cpp
//
// implementation for guiapp.h
//
//




#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <Xm/Xm.h>
#include <Xm/AtomMgr.h>


#include    "guiapp.h"
#include    "assert.h"
#include    "colorDefaults.h"
#include    "guiTopWindow.h"
#include    "consedParameters.h"
#include    "tagTypes.h"
#include    "consed.h"
#include    "nPrimerFalseMatchScoreArray.h"
#include    "popupInfoOrErrorMessageNoFormat.h"
#include    "decisionbox.h"
#include    "fileselector.h"
#include    "consedResources.h"
#include    "guitedwin.h"
#include    "bGuiGetAnswerYesNo.h"
#include    "colormode.h"
#include    "hp_exception_kludge.h"



//
// static class members
//
GuiApp* GuiApp::pGlobalGuiApp_ = 0;
bool GuiApp::bGuiAppCreated_ = false;

// specifies the fallback (i.e. default) values 
// of these resources for this application
static String aszFallbackResources[] = {

  // "system" font, used on labels, buttons, menus, etc.
   //  "consed*fontList: helvetica",

  // drawing font used in contigwin
  "consed*font: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1",
  "consed*fontList: -misc-fixed-bold-r-normal--13-100-100-100-c-70-iso8859-1",
  "consed*foreground: Black",
  // colors and shadows
//  "consed*troughColor: Grey45",
  "consed*troughColor: Black",
  "consed*background: Grey77",
  "consed*topShadowColor: Grey88",
  "consed*bottomShadowColor: Grey45",
  "consed*shadowThickness: 2",
  // these need to be reversed appearance consistent with diboxes, etc.
  "consed*mainwin.topShadowColor: Grey45",
  "consed*mainwin.bottomShadowColor: Grey88",

  // colors in trace window

  "consed*scaleDrawingArea.background: black",
  "consed*consensusDrawingArea.background: black",
  "consed*editableBasesDrawingArea.background: black",
  "consed*tagsDrawingArea.background: black",
  "consed*phredCalledBasesDrawingArea.background: black",
  "consed*ABICalledBasesDrawingArea.background: black",
  "consed*tracesDrawingArea.background: black",

  //  "consed*assemblyView*assemblyViewDrawingArea.background: white",

  // time in milliseconds--very long time for recognizing double clicks
  "consed*doubleClickInterval: 400",

  // "consed*contigwin.background: Black",
  // "consed*scaleNumbers.foreground: Yellow",
  // "consed*scaleGraphics.foreground: Yellow",

  // scale widgets require messing with for some obscure reason
  "consed*verticalScale.height: 18",
  "consed*horizontalScale.height: 18",

  // not sure this belongs here, but users will probably want
  // to mess with these ranges and defaults
  "consed*verticalScale.value: 100",
  "consed*verticalScale.maximum: 400",
  "consed*verticalScale.minimum: 1",
  "consed*horizontalScale.value: 10",
  "consed*horizontalScale.maximum: 50",
  "consed*horizontalScale.minimum: 3",

  // infobuttons are used to display current filename, fragment, etc.
  // pressing (usually) them supplies more info
  //  "consed*infobutton.fontList: helvetica",
  //  "consed*textfield.fontList: helvetica",
  "consed*textfield.background: Grey70",

  // for textbox object
  "consed*textBox.fontList: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1",
  "consed*navtextfield*fontList: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1",
  "consed*navigator*fontList: -misc-fixed-medium-r-normal--15-140-75-75-c-90-iso8859-1",

  "consed.title: Consed Main Window",


  //FOR COPIES
  //"consed*scaleDrawingArea.background: grey70",
  //"consed*consensusDrawingArea.background: grey70",
  // "consed*editableBasesDrawingArea.background: grey70",
  // "consed*tagsDrawingArea.background: grey70",
  // "consed*phredCalledBasesDrawingArea.background: grey70",
  // "consed*ABICalledBasesDrawingArea.background: grey70",
  // "consed*tracesDrawingArea.background: grey70",
  // "consed*contigwin.background: grey70",
  // "consed*scaleNumbers.foreground: grey70",
  // "consed*scaleGraphics.foreground: grey70",

  "consed*contigwin.background: black",
  "consed*scaleNumbers.foreground: black",
  "consed*scaleGraphics.foreground: black",



  NULL // list is null-terminated

};


// struct into which returned application resources
// will be written
typedef struct {
   XFontStruct *pFont;           // The font struct 
} AppDataType, *AppDataPtrType;
 
AppDataType appData;

// specifies the list of resources to be returned by 
// the call to XtGetApplicationResources
static XtResource appResources[] = {
   {
      XtNfont, 
      XtCFont, 
      XtRFontStruct, 
      sizeof( XFontStruct *),
      XtOffset(AppDataPtrType, pFont), 
      XtRString, 
      (char*) ""  
     }
};

      

int     nErrorHandler( Display* pDisplay, XErrorEvent* pErrorEvent ) {
   assert( false );
   return( 1 );
}


void GuiApp :: maybeSetXKeySymDB() {

#ifdef LINUX_COMPILE   

   
   char* szXKeySymDB = getenv( "XKEYSYMDB" );

   if ( szXKeySymDB ) {
      fprintf( stderr, "XKEYSYMDB is already set to %s so not setting it again--that's ok\n", szXKeySymDB );
      return;
   }


   FileName filXKeySymDBPath;
   if ( pCP->filMaybeXKEYSYMDBPath_.bFileByThisNameExists() )
      filXKeySymDBPath = pCP->filMaybeXKEYSYMDBPath_;
   else if ( pCP->filMaybeXKEYSYMDBPath2_.bFileByThisNameExists() )
      filXKeySymDBPath = pCP->filMaybeXKEYSYMDBPath2_;
   else {
      fprintf( stderr, "not setting XKEYSYMDB.  This is ok if you don't get any errors saying something about \"Warning: translation table...\"" );
      fflush( stderr );
      return;
   }

   //   fprintf( stderr, "setting XKEYSYMBDB to %s\n", filXKeySymDBPath.data() );

   // the 1 means to overwrite
   assert( setenv( "XKEYSYMDB", filXKeySymDBPath.data(), 1 ) == 0 );

   // check that it was set
   char* szXKeySymDB2 = getenv( "XKEYSYMDB" );

   if ( szXKeySymDB2 ) {
      RWCString soTemp( szXKeySymDB2 );
//       fprintf( stderr, "set XKEYSYMDB to %s\n", szXKeySymDB2 );
//       fflush( stderr );
   }
   else {
      fprintf( stderr, "tried but failed to set XKEYSYMDB" );
      fflush( stderr );
   } 

#endif

}






GuiApp :: GuiApp(const char* szName,
                 int argc,
                 char* argv[],
                 const bool bTopWindow ) 
{

   //
   // fail crudely if one already exists - we may not have
   // a gui at all yet
   //
   if (bGuiAppCreated_) {
      cerr << "Fatal program error:  GuiApp ctor called twice." << endl;
      cerr.flush();
      exit(-1);
   }

   // flag true forever 
   bGuiAppCreated_ = true;

   // save ptr to self in static global member
   pGlobalGuiApp_ = this;

   // only do this for linux

#ifdef LINUX_COMPILE   
   maybeSetXKeySymDB();
#endif

   //
   // create the toplevel widget
   //
   widTopLevel_ = XtAppInitialize(&ctxAppContext_,
                                  szName,
                                  NULL, 0,
                                  (int *)&argc, argv,
                                  aszFallbackResources,
                                  NULL, (Cardinal )0);

   //   XSetErrorHandler( nErrorHandler );

   Arg  aArg[20];
   int  nArgs;

   nArgs = 0;
   XtSetArg( aArg[nArgs], XmNallowShellResize, True ); nArgs++;
   XtSetValues( widTopLevel_, aArg, nArgs );
   


   //
   // pick up the application resources
   //
   XtGetApplicationResources(   widTopLevel_,
                                &appData, 
                                appResources, 
                                XtNumber(appResources),
                                NULL, (Cardinal) 0 );


   bool bEnoughRoomInColormap = true;
   saveColors( bEnoughRoomInColormap );

   if (!bEnoughRoomInColormap) {
      cout << "There is some other application that is a color hog." << endl;
      cout << "It might be netscape" << endl;
      cout << "Consed can continue, but will use its own colormap" << endl;
      cout << "which will cause some flashing when moving the mouse" << endl;
      cout << "between different windows.  If you don't like this, " << endl;
      cout << "you should restart netscape as netscape -install " << endl;
      cout << "and then restart consed." << endl;
   }

   setUpColormap( bEnoughRoomInColormap );


   //
   // save a copy of the font struct as private data
   //
   pXfsDrawFont_ = appData.pFont;

   //
   // calculate some font information
   //

   // here's a text containing most of what we care about
   char* szSampleFragment =
     "gg**aaccttAGAACATGCTCCTTTAGCTC**GGAGAAGTTTGTTATTACG";

   int  nDir;
   int  nAscent;
   int  nDescent;
   XCharStruct xCharStruct;

   XTextExtents(appData.pFont, 
                szSampleFragment, 
                strlen(szSampleFragment),
                &nDir, 
                &nAscent, 
                &nDescent, 
                &xCharStruct);

   nFontAscent_ = nAscent;
   nFontHeight_ = nAscent + nDescent;
   nFontDescent_ = nDescent;
   nFontWidth_  = xCharStruct.width / strlen( szSampleFragment );   
   nFontLBearing_ = xCharStruct.lbearing;
   nFontRBearing_ = xCharStruct.rbearing - 
     ( nFontWidth_ * (strlen( szSampleFragment ) - 1 ) );



   xmFontList_ = XmFontListCreate( pXfsDrawFont_, XmSTRING_DEFAULT_CHARSET );


   if ( bTopWindow ) {
      pGuiTopWindow_ = new guiTopWindow();
   }


}



void GuiApp :: makeVisible() {
   XtRealizeWidget(widTopLevel_); 

   // set initial input focus to first read name box

   // why isn't this done in guiTopWindow ctor?  Because it only works
   // after the XtRealizeWidget above
   XmProcessTraversal( pGuiTopWindow_->widReadWithAsterisks_,
                       XmTRAVERSE_CURRENT );

// unmap doesn't keep the brick unmapped when a dialog pops up
//   XtUnmapWidget( widTopLevel_ );
// iconify iconifies all dialogs, too, so users can't see them
//   XIconifyWindow( XtDisplay( widTopLevel_ ), XtWindow( widTopLevel_ ),
//                  0 );

   XtVaSetValues( widTopLevel_, XmNcolormap, cmap_, NULL );
   Display*  pDisplay = XtDisplay( widTopLevel_ );
   XSetWindowColormap( pDisplay, XtWindow( widTopLevel_ ), cmap_ );
}



// This macro makes saveColorAndCheckColorMap( ColorHighlightBackground )
//
// into:
//
//    ColorDefaults::pGetColorDefaults()->soColorHighlightBackground_ =
//      appData.szColorHighlightBackground;
//
//    if (bEnoughRoomInColormap) {
//       int nStatus = XAllocNamedColor( pDisplay,
//                                       colormap,
//                                       soColorHighlightBackground_,
//                                       &xcolor,
//                                       &xcolorHardware );
//       if (nStatus != 1 )
//          bEnoughRoomInColormap = false;
//    }  


#define saveColorAndCheckColormap( ColorName ) \
\
     ColorDefaults::pGetColorDefaults()->so ## ColorName ## _ = \
     consedResources::pCurrentResources_->so ## ColorName ## _; \
     if (bEnoughRoomInColormap) { \
        int nStatus = XAllocNamedColor( \
               pDisplay, \
               cmapDefault, \
               ColorDefaults::pGetColorDefaults()->so ## ColorName ## _, \
               &xcolor, \
               &xcolorHardware ); \
                                  \
        if (nStatus != 1 ) \
           bEnoughRoomInColormap = false; \
     }




void GuiApp :: saveColors( bool& bEnoughRoomInColormap ) {
   ColorDefaults* pTempColorDefaults = new ColorDefaults();

   Display* pDisplay = XtDisplay( widTopLevel_ );

   int nScreen =  DefaultScreen(pDisplay);
 
   Colormap cmapDefault = DefaultColormap( pDisplay, nScreen);

   XColor xcolor;
   XColor xcolorHardware;
   

   bEnoughRoomInColormap = true;


#include "saveColors.cpp.part2"


   // now try to check for some other colors used by Motif

   justCheckColormap( "Grey77", bEnoughRoomInColormap );
   justCheckColormap( "Grey88", bEnoughRoomInColormap  );
   justCheckColormap( "Grey45", bEnoughRoomInColormap  );
   justCheckColormap( "Black",  bEnoughRoomInColormap  );

   // These are just to make sure there is enough room for the
   // the user to customize his colors.

   justCheckColormap( "seashell",  bEnoughRoomInColormap  );
   justCheckColormap( "honeydew",  bEnoughRoomInColormap  );
   justCheckColormap( "mint cream",  bEnoughRoomInColormap  );
   justCheckColormap( "navy blue",  bEnoughRoomInColormap  );
   justCheckColormap( "coral",  bEnoughRoomInColormap  );
   justCheckColormap( "RosyBrown",  bEnoughRoomInColormap  );
   justCheckColormap( "dark salmon",  bEnoughRoomInColormap  );
   justCheckColormap( "SlateGray3",  bEnoughRoomInColormap  );



   pColorOfRestrictionFragmentPairTooFarApart_ = new GuiColorText(
      ColorDefaults::pGetColorDefaults()->soColorRestrictionFragmentPairTooFarApart_,
      "black" );

   pColorOfUnmatchedRestrictionFragment_ = new GuiColorText(
      ColorDefaults::pGetColorDefaults()->soColorUnmatchedRestrictionFragment_,
      "black" );

   pColorOfRestrictionFragmentInContig_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorRestrictionFragmentInContig_,
       "black" );  // I don't see this being using for anything, so
                   // I'm not making it configurable

   pColorOfRestrictionFragmentPartlyOffContig_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorRestrictionFragmentPartlyOffContig_,
       "black" );

   pColorOfRestrictionFragmentEntirelyOffContig_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorRestrictionFragmentEntirelyOffContig_,
       "black" );

   pColorOfActualGelRestrictionFragment_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorActualGelRestrictionFragment_,
       "black" );

   pColorOfRestrictionDigestScale_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorRestrictionDigestScale_,
       "black" );

   pColorOfRestrictionDigestCursorIndicator_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorRestrictionDigestCursorIndicator_,
       "black" );


   pColorOfRestrictionFragmentsOnTopOfEachOther_ = new GuiColorText(
       ColorDefaults::pGetColorDefaults()->soColorRestrictionFragmentsOnTopOfEachOther_,
       "black" );

   pColorReadPrefixDefault_ = new GuiColorText( 
       ColorDefaults::pGetColorDefaults()->soColorReadPrefixDefault_,
       "white" );




   pColorMeansMatch_ = new ColorMeansMatch( );
   pColorMeansQuality_ = new ColorMeansQuality( );
   pColorMeansEdited_ = new ColorMeansEdited( );
   pColorMeansQualityAndTags_   = new ColorMeansQualityAndTags( );
   pColorMeansEditedAndTags_ = new ColorMeansEditedAndTags( );

}



void GuiApp :: getFallbackResources( RWCString& soFallbackResources ) {
   soFallbackResources = "";

   bool bFirstTime = true;
   int n = 0;
   while( aszFallbackResources[n] != NULL ) {
      if (bFirstTime) 
        bFirstTime = false;
      else
        soFallbackResources += "\n";

      soFallbackResources += aszFallbackResources[n];
      ++n;
   }
   

}



void GuiApp :: mainLoop() { 
  XEvent xevent;

  for(;;) {
    XtAppNextEvent( ctxAppContext_, &xevent );
    XtDispatchEvent( &xevent );
    // removed this.  Otherwise on Gnome the popup windows would
    // often be grey with no text.
//     if ( (xevent.type == Expose ) && ( xevent.xexpose.count > 0 ) ) {
//        cerr << "ignoring expose event at " <<  time( NULL ) << endl;
//     }
//     else 
  }
}    





////////////////////////////////////////////////////////////
//
// PURPOSE: error message
//
// HOW TO USE IT:  Just like printf
//
// 
// INPUTS:  a format string and arguments
//
// REV: (David Gordon) May 1995
//
////////////////////////////////////////////////////////////


// this is in the guiapp namespace
void GuiApp :: popupErrorMessage( const char *szErrorFormat, ... ) {
   char     szErrorMessage[10000];

   va_list  args;
   va_start(args, szErrorFormat);
   vsprintf( szErrorMessage, szErrorFormat, args );
   va_end(args);
   
   popupInfoOrErrorMessageNoFormat( NULL, // shell of parent
                                    true, // error message not info
                                    szErrorMessage );
}

// variant for infobox
void GuiApp :: popupInfoMessage( const char *szErrorFormat, ... ) {
   char     szErrorMessage[10000];

   va_list  args;
   va_start(args, szErrorFormat);
   vsprintf( szErrorMessage, szErrorFormat, args );
   va_end(args);

   if ( !consedParameters::pGetConsedParameters()->bOKToUseGui_ )
      return;

   popupInfoOrErrorMessageNoFormat( NULL, // shell of parent
                                    false, // bErrorNotInfoMessage
                                    szErrorMessage );
}










char cbSelectionConversion( Widget wid, 
                            Atom* pSelection,
                            Atom* pTarget,
                            Atom* pReturnType,
                            XtPointer* pValue,
                            unsigned long* pLength,
                            int* pFormat ) {
   

   Atom COMPOUND_TEXT = XmInternAtom( XtDisplay( wid),
                                      "COMPOUND_TEXT", False );

   Atom TARGETS = XmInternAtom( XtDisplay( wid ), "TARGETS", False );

   XSelectionRequestEvent *pEvent = XtGetSelectionRequest( wid, 
                                           *pSelection,
                                           (XtRequestId) NULL );

   
   if ( *pTarget == XA_STRING ) {

      char  **pszValue;
      XTextProperty xprop;
      int   status = 0;
      XmString  *xmsSelectedItems;
      int   nSelectedCount = 1;
      int   i;

      pszValue = (char**) XtMalloc( ( nSelectedCount + 1) * sizeof( char* ) );

      pszValue[0] = 
         (char*) GuiApp:: pGetGuiApp()->soSelectedBasesForPasting_.data();

      pszValue[1] = NULL;

      status = XmbTextListToTextProperty( XtDisplay( wid ),
                                          pszValue,
                                          nSelectedCount,
                                          (XICCEncodingStyle) XStringStyle,
                                          &xprop );


     if (status == Success || status > 0 ) {
         *pReturnType = XA_STRING;
         *pFormat = 8;
         *pValue = (XtPointer) XtMalloc( (unsigned) xprop.nitems );

         memcpy( (void*) *pValue,
                 (void*) xprop.value,
                 (unsigned) xprop.nitems);

         XFree( (char*) xprop.value );

         *pLength = xprop.nitems;
         return True;
      }
      else {
        return False;
      }

      

   }
   else if ( *pTarget == TARGETS ) {
      Atom *pTargets;

      *pLength = 2;
      *pValue = (XtPointer)XtMalloc( sizeof(Atom) * (*pLength) );
      pTargets = *(Atom**) pValue;
      *pTargets++ = TARGETS;
      *pTargets++ = XA_STRING;
      *pReturnType = XA_ATOM;
      *pFormat = 32;
      return True;
   }
   else
      return False;

}





void cbLoseSelectionOwnership( Widget wid, Atom *pSelection ) {
}


void GuiApp :: makeSelectionForPasting( const RWCString& soBasesToPaste ) {

   soSelectedBasesForPasting_ = soBasesToPaste;

   Time time2 =
      XtLastTimestampProcessed( XtDisplay( widTopLevel_ ) );

   bool b = XtOwnSelection( widTopLevel_,
                            XA_PRIMARY,
                            time2,
                            cbSelectionConversion,
                            cbLoseSelectionOwnership,
                            NULL );
   if ( !b ) {
      cerr << "Warning--didn't get selection so cut/paste may not have worked\nPlease try again" << endl;
   }
}




void GuiApp :: setUpColormap( const bool bEnoughRoomInColormap ) {

   Display*  pDisplay = XtDisplay( widTopLevel_ );
   int nScreen =  DefaultScreen(pDisplay);
 

   if ( bEnoughRoomInColormap ) {
      cmap_ = DefaultColormap( pDisplay, nScreen);
   }
   else {

      Window   winRoot = DefaultRootWindow( pDisplay );

      cmap_ = XCreateColormap( pDisplay, winRoot, 
                           DefaultVisual( pDisplay, DefaultScreen( pDisplay )),
                           AllocNone );

      XtVaSetValues( widTopLevel_, XmNcolormap, cmap_, NULL );

      copyABunchOfColormapCells();
   }
}



void GuiApp :: copyABunchOfColormapCells() {

   Display*  pDisplay = XtDisplay( widTopLevel_ );
   int nScreen =  DefaultScreen(pDisplay);
   Colormap cmapDefault = DefaultColormap( pDisplay, nScreen);

   const int nNumberOfColorCellsToCopy = 100;
   for( int nCell = 0; nCell < nNumberOfColorCellsToCopy; ++nCell ) {
      XColor xc;
      xc.pixel = nCell;

      XQueryColor( pDisplay, cmapDefault, &xc );
      
      XAllocColor( pDisplay, cmap_, &xc );
   }

}



void GuiApp :: justCheckColormap( char* szColorName, 
                                  bool& bEnoughRoomInColormap ) {

   if (bEnoughRoomInColormap) { 
      Display* pDisplay = XtDisplay( widTopLevel_ );
      int nScreen =  DefaultScreen(pDisplay);
      Colormap cmapDefault = DefaultColormap( pDisplay, nScreen);
      XColor xcolor;
      XColor xcolorHardware;

      int nStatus = XAllocNamedColor( 
                                     pDisplay, 
                                     cmapDefault, 
                                     szColorName, 
                                     &xcolor, 
                                     &xcolorHardware ); 

      if (nStatus != 1 ) 
         bEnoughRoomInColormap = false; 
      else {
         unsigned long pixels[1];
         pixels[0] = xcolorHardware.pixel;
         XFreeColors( pDisplay, cmapDefault, pixels,
                      1, // # of colors to free
                      0 // # of planes
                      );

      }
   }
}



////////////////////////////////////////////////////////////
//
// PURPOSE: To force the user to acknowledge a question
//      and respond before the program continues.  
//      (It does not prevent the user from using other 
//      applications!)
//
// HOW TO USE IT:  Just like printf
//
// 
// INPUTS:  a format string and arguments
// RETURNS:  boolean true user pressed "OK", false otherwise
//
// REV: (David Gordon) May 1995
//       now uses DecisionBox object.  chrisa 17-may-95
//       wish it didn't (DG)
//
////////////////////////////////////////////////////////////


// this is in the guiapp namespace
bool GuiApp::popupDecisionMessage( const char *szErrorFormat, ... ) {
   char     szDecisionMessage[10000];

   va_list  args;
   va_start(args, szErrorFormat);
   vsprintf( szDecisionMessage, szErrorFormat, args );
   va_end(args);


   DecisionBox db(szDecisionMessage);
   db.makeVisible();  // blocks here till user acks

   return db.bUserPressedOk();
}




// wrapper in the GuiApp namespace
FileName GuiApp::popupFileSelector(const char* szTitle, 
                                   const char* szDirMask,
                                   const char* szFileName) {
   FileSelector fs;
   return fs.popUpAndGetFilePath(szTitle, szDirMask, szFileName);
}


void GuiApp :: findTopWindow() {

   // removed Oct 2008 because UWGC has XWin32 on multiple window
   // causes window manager handle to be removed so the window
   // can't be moved
   //   XtUnmapWidget( widTopLevel_ );

   XtMapWidget( widTopLevel_ );


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




void GuiApp :: changeDefaultToLightBackground() {


   Display* pDisplay = XtDisplay( widTopLevel_ );

   XrmDatabase xrmdb = XrmGetDatabase( pDisplay );


   XrmPutLineResource( &xrmdb, "consed*contigwin.background:    black" );

   XrmPutLineResource( &xrmdb, "consed*scaleDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*consensusDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*editableBasesDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*tagsDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*phredCalledBasesDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*ABICalledBasesDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*tracesDrawingArea.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*contigwin.background: grey70" );
   XrmPutLineResource( &xrmdb, "consed*scaleNumbers.foreground: grey70" );
   XrmPutLineResource( &xrmdb, "consed*scaleGraphics.foreground: grey70" );
   
   ColorDefaults::pGetColorDefaults()->soColorTracesA_ = "chartreuse";
   ColorDefaults::pGetColorDefaults()->soColorTracesC_ = "royal blue";
   ColorDefaults::pGetColorDefaults()->soColorTracesG_ = "Black";
   ColorDefaults::pGetColorDefaults()->soColorTracesT_ = "Red";

   ColorDefaults::pGetColorDefaults()->soColorSequencingDirectionArrow_ = 
      "Blue";
   ColorDefaults::pGetColorDefaults()->soColorConsensusLabel_ = "Blue";
   ColorDefaults::pGetColorDefaults()->soColorConsensusLabelBackground_ = 
      "Grey70";

   ColorDefaults::pGetColorDefaults()->soColorScale_ = "Black";

   ColorDefaults::pGetColorDefaults()->soColorScaleBackground_ = "Grey70";

   GuiTedWin::allocateColors();

   GuiTedWin::pGuiColorTextA_->changeLineWidth( 3 );
   GuiTedWin::pGuiColorTextC_->changeLineWidth( 3 );
   GuiTedWin::pGuiColorTextG_->changeLineWidth( 3 );
   GuiTedWin::pGuiColorTextT_->changeLineWidth( 3 );



}




void GuiApp :: printWindow( ) {

   bGuiGetAnswerYesNo( pCP->soPrintWindowInstructions_.data() );

   int nReturnStatus = system( pCP->soPrintWindowCommand_.data() );

   if ( nReturnStatus != 0 ) {
      char* szErrorMessage = strerror( nReturnStatus );
      if ( szErrorMessage ) {
         popupErrorMessage( "Something went wrong running %s.  Gave error code %d which means %s",
                            pCP->soPrintWindowCommand_.data(),
                            nReturnStatus,
                            szErrorMessage );
      }
      else {
         popupErrorMessage( "Something went wrong running %s.  Gave error code %d.  See xterm for more details",
                            pCP->soPrintWindowCommand_.data(),
                            nReturnStatus );
      }
   }
}





bool GuiApp :: bGetGuiColorTextForReadPrefixByColor( 
                               GuiColorText*& pGuiColorText,
                               const RWCString& soForegroundColor ) {

   RWCString soColorToFind = soForegroundColor;
   soColorToFind.toLower();
   
   for( int nColor = 0; nColor < aColorNamesForReadPrefixes_.length();
        ++nColor ) {

      if ( soColorToFind == aColorNamesForReadPrefixes_[ nColor ] ) {
         pGuiColorText = aGuiColorTextForReadPrefixes_[ nColor ];
         return( true );
      }
   }

   return( false );
}


GuiColorText* GuiApp :: pGetGuiColorTextForReadPrefixColor( 
                              const RWCString& soForegroundColor ) {

   GuiColorText* pGuiColorText = NULL;
   if ( bGetGuiColorTextForReadPrefixByColor( pGuiColorText,
                                              soForegroundColor ) )
      return( pGuiColorText );


   RWCString soColor = soForegroundColor;
   soColor.toLower();


   pGuiColorText = new GuiColorText( soColor, "white" );
   aGuiColorTextForReadPrefixes_.insert( pGuiColorText );

   aColorNamesForReadPrefixes_.insert( soColor );
   
   return( pGuiColorText );
}


//
// cursor blink interval, in milliseconds
//
static const int nBlinkOnInterval = 900;  // a slow 4/4 time...
static const int nBlinkOffInterval = 100;  


void xtBlinkCallback(XtPointer clientData,  // params ignored
                     XtIntervalId* pId) {

   TRY_CATCH_WRAPPER( GuiApp::pGetGuiApp()->blinkAgain() );

}


void GuiApp :: blinkAgain() {

   // toggle the blink state
   bBlinkState_ = ! bBlinkState_;


   // reset the timer
   XtAppAddTimeOut( ctxGetAppContext(),
                    ( bBlinkState_ ?
                      nBlinkOnInterval : nBlinkOffInterval ),
                    xtBlinkCallback,
                    0);  // no user data needed

   ConsEd::pGetConsEd()->blinkAllCursors( bBlinkState_ );
}

   


void GuiApp :: startBlinking() {

   bBlinkState_ = false;

   XtAppAddTimeOut( ctxGetAppContext(),
                    nBlinkOnInterval,
                    xtBlinkCallback,
                    0 ); // no user data needed

}