#define RCSID "$Id: Message.c,v 1.84 2006/02/26 16:34:28 geuzaine Exp $"
/*
 * Copyright (C) 1997-2006 P. Dular, C. Geuzaine
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 *
 * Please report all bugs and problems to <getdp@geuz.org>.
 */

#include <signal.h>
#include "GetDP.h"
#include "GetDPVersion.h"
#include "CurrentData.h"
#include "LinAlg.h"
#include "GmshClient.h"
#include "OS.h"

#if !defined(GETDP_EXTRA_VERSION)
#error 
#error include/GetDPVersion.h is not up-to-date. 
#error Please run 'make tag'.
#error
#endif


extern int     InteractiveLevel, InteractiveInterrupt ;

void FinalizeAndExit(void);

/* ------------------------------------------------------------------------ */
/*  I n f o                                                                 */
/* ------------------------------------------------------------------------ */

char acronym[]   = "GetDP, a General environment for the treatment of Discrete Problems\n";
char copyright[] = "Copyright (C) 1997-2006 Patrick Dular and Christophe Geuzaine\n";

char version[]   = "Version      : %s\n";
char license[]   = "License      : %s\n";
char os[]        = "Build OS     : %s\n";
char date[]      = "Build date   : %s\n";
char host[]      = "Build host   : %s\n";
char packager[]  = "Packager     : %s\n";
char url[]       = "Web site     : http://www.geuz.org/getdp/\n";
char email[]     = "Mailing list : getdp@geuz.org\n";

#if defined(HAVE_SPARSKIT)
#if defined(HAVE_ILU_FLOAT)
char solver[]    = "Solver       : Sparskit (real arithmetic, single precision preconditioning)\n";
#else
char solver[]    = "Solver       : Sparskit (real arithmetic)\n";
#endif
#else
#if defined(PETSC_USE_COMPLEX)
char solver[]    = "Solver       : PETSc (complex arithmetic)\n";
#else
char solver[]    = "Solver       : PETSc (real arithmetic)\n";
#endif
#endif

char help[] = 
#if defined(HAVE_SPARSKIT)
  "Usage: %s [file] [options]\n"
#else
  "Usage: [mpirun [MPI options]] %s [file] [options] [PETSc options]\n"
#endif
  "Processing options:\n"
  "  -pre 'Resolution'         pre-processing\n"
  "  -cal                      processing\n"
  "  -pos 'PostOperation(s)'   post-processing\n"
  "  -ipos 'PostProcessing(s)' interactive post-processing\n"
  "  -msh file                 read mesh (in msh format) from file\n"
  "  -restart                  resume processing from where it stopped\n"
  "  -solve 'Resolution'       same as -pre 'Resolution' -cal\n"
  "  -split                    save processing results in separate files\n"
  "  -res file(s)              load processing results from file(s)\n"
  "  -name string              use string as generic file name\n"
  "  -adapt file               read adaptation constraints from file\n"
  "  -order num                restrict maximum interpolation order\n"
#if defined(HAVE_SPARSKIT)
  "Linear solver options:\n"
  "  -solver file              specify parameter file (default: solver.par)\n"
  "  -'Parameter' num          override value of solver parameter 'Parameter'\n"
#endif
  "Output options:\n"
  "  -bin                      use binary format for output files\n"
  "  -log                      save processing history in log file\n"
  "  -socket string            communicate through socket string\n"
  "Other options:\n"
  "  -check                    interactive check of problem structure\n"
  "  -v num                    set verbosity level (default: 4)\n"
  "  -p num                    set progress indicator update (default: 10)\n"
  "  -version                  show version number\n"
  "  -info                     show detailed version information\n"
  "  -help                     show this message\n"
  ;

void Info (int level, char *arg0){
  
  switch(level){
  case 0 :
    fprintf(stderr, acronym);
    fprintf(stderr, copyright);
    fprintf(stderr, help, arg0);
    break;
  case 1:
    fprintf(stderr, "%s\n", GETDP_VERSION);
    break;
  case 2:
    fprintf(stderr, version, GETDP_VERSION);
    fprintf(stderr, license, GETDP_SHORT_LICENSE);
    fprintf(stderr, os, GETDP_OS);
    fprintf(stderr, date, GETDP_DATE);
    fprintf(stderr, host, GETDP_HOST);
    fprintf(stderr, packager, GETDP_PACKAGER);
    fprintf(stderr, solver);
    fprintf(stderr, url);
    fprintf(stderr, email);
    break;
  }

  FinalizeAndExit();
}

/* ------------------------------------------------------------------------ */
/*  S i g n a l                                                             */
/* ------------------------------------------------------------------------ */

void Signal (int sig_num){

  /* It is VERY wrong to call stdio functions in a signal handler. But
     who cares? ;-) */

  if(sig_num == SIGINT){
    if(!InteractiveLevel){
      if(TreatmentStatus == _CAL && Flag_VERBOSE > 1){
	Msg(BIGINFO, "Switching to low verbosity mode"); 
	Flag_VERBOSE = 1;
      }
      else Msg(GERROR, "Interrupt (generated from terminal special character)"); 
    }
    else
      InteractiveInterrupt = 1;
    return;
  }
  switch (sig_num){
  case SIGSEGV : 
    Msg(BIGERROR, "Segmentation violation (invalid memory reference)");
    break;
  case SIGFPE : 
    Msg(BIGERROR, "Floating point exception (division by zero?)");
    break;
  default :
    Msg(GERROR, "Unknown signal");
    break;
  }
}


/* ------------------------------------------------------------------------ */
/*  M s g                                                                   */
/* ------------------------------------------------------------------------ */

void Print_GetDPContext(FILE *stream){
#if defined(HAVE_DEBUG_STACK)
  char FileName[256], FileVersion[256], FunctionName[256], FileAuthor[256];
  char Dum[256], FileDate[256];
  int  i, Line ;

  fprintf(stream, "Debug     : Stack trace (depth = %d) is printed below\n",
	  GetDP_CurrentStackIndex);
  for(i = 0; i < GetDP_CurrentStackIndex; i++){
    sscanf(GetDP_CurrentSourceFile[i],
	   "$Id: %s %s %s %s %s", FileName, FileVersion, FileDate, Dum, FileAuthor);
    FileName[strlen(FileName)-2] = '\0' ;
    strcpy(FunctionName, GetDP_CurrentFunction[i]);
    Line = GetDP_CurrentSourceLine[i];
    fprintf(stream, "'%s' in '%s', line %d (version %s by %s on %s)\n", 
	    FunctionName, FileName, Line, FileVersion, FileAuthor, FileDate);
  }
#endif
}


void PrintMsg(FILE *stream, int level, int Verbosity, 
	      va_list args, char *fmt, int *abort) {

  int  verb, nl, gmshlevel;
  char *str, prefix[1000], sockmsg[1000];

  switch(level){
  case CHECK     : verb = 0; nl = 0; str = NULL; break;
  case GERROR    : /* fall-through */
  case BIGERROR  : verb = 0; nl = 1; str = ERROR_STR; *abort = 1; break;
  case WARNING   : verb = 0; nl = 1; str = WARNING_STR; break;
  case OPERATION : verb = 2; nl = 1; str = OPERATION_STR; break;
  case LOADING   : verb = 2; nl = 1; str = LOADING_STR; break;
  case INFO      : verb = 3; nl = 1; str = INFO_STR; break;
  case INFO1     : verb = 3; nl = 0; str = INFO_STR; break;
  case INFO2     : verb = 3; nl = 0; str = NULL; break;
  case INFO3     : verb = 3; nl = 1; str = NULL; break;
  case BIGINFO   : verb = 1; nl = 1; str = BIGINFO_STR; break;
  case DEBUG     : verb =99; nl = 0; str = NULL; break;
  case DEBUG2    : verb =98; nl = 0; str = NULL; break;
  case SPARSKIT  : verb = 3; nl = 0; str = SPARSKIT_STR; break;
  case PETSC     : verb = 3; nl = 1; str = PETSC_STR; break;
  case ITER      : verb = 4; nl = 0; str = NULL; break;
  case DIRECT    : /* fall-through */
  default        : verb = 1; nl = 1; str = NULL; break;
  }

  if(Verbosity >= verb || stream == LogStream){

    if(Flag_SOCKET > 0 && stream != LogStream){
      if(str) strcpy(prefix, str); else strcpy(prefix, "");
      vsprintf(sockmsg, fmt, args);
      if(!nl) sockmsg[strlen(sockmsg)-1] = '\0' ;
      strcat(prefix, sockmsg);
      switch(level){
      case GERROR   : /* fall-through */
      case BIGERROR : gmshlevel = GMSH_CLIENT_ERROR; break;
      case WARNING  : gmshlevel = GMSH_CLIENT_WARNING; break;
      default       : gmshlevel = GMSH_CLIENT_INFO; break;
      }
      Gmsh_SendString(Flag_SOCKET, gmshlevel, prefix);
    }
#if !defined(WIN32) 
    else{ /* on everything but windows, don't print anything if getdp
	     is called with a socket arg: it would be piped to
	     .xsession-errors */
#endif
      if(str) fprintf(stream, str); 
      vfprintf(stream, fmt, args); 
      if(nl) fprintf(stream, "\n");
      if(level == BIGERROR){
	fprintf(stream, WHITE_STR "------------------------------------------------------\n");
	fprintf(stream, WHITE_STR "You have discovered a bug in GetDP! You may report it\n");
	fprintf(stream, WHITE_STR "by e-mail (together with any helpful data permitting to\n");
	fprintf(stream, WHITE_STR "reproduce it) to <getdp@geuz.org>\n");
      }
      if(*abort){
	Print_GetDPContext(stream);
      }
#if !defined(WIN32) 
    }
#endif

  }

  fflush(stream);
}

void PrintResources(FILE *stream, char *fmt, double s, long mem){
  char msg[1000];
  if(mem)
    sprintf(msg, RESOURCES_STR "%scpu %g s / mem %ld kb\n", fmt, s, mem);
  else
    sprintf(msg, RESOURCES_STR "%scpu %g s\n", fmt, s);

  if(Flag_SOCKET > 0)
    Gmsh_SendString(Flag_SOCKET, GMSH_CLIENT_INFO, msg);
  else
    fprintf(stream, msg);
}

void Msg(int level, char *fmt, ...){
  va_list  args;
  int      abort = 0;
  double   s;
  long     mem ;

  if(Current.RankCpu && level != PETSC) return ;

  if(level == RESOURCES){
    if(Flag_LOG || Flag_VERBOSE > 3) GetResources(&s, &mem) ;
    if(Flag_VERBOSE > 3) PrintResources(stderr, fmt, s, mem) ;
    if(Flag_LOG) PrintResources(LogStream, fmt, s, mem) ;
  }
  else if(level == SUMMARY){
    if(Flag_LOG || Flag_VERBOSE > 0) GetResources(&s, &mem) ;
    if(Flag_VERBOSE > 0) PrintResources(stderr, fmt, s, mem) ;
    if(Flag_LOG) PrintResources(LogStream, fmt, s, mem) ;
  }
  else{
    va_start (args, fmt);
    PrintMsg(stderr,level, Flag_VERBOSE, args, fmt, &abort) ;
    if(Flag_LOG) {
      PrintMsg(LogStream, level, Flag_VERBOSE, args, fmt, &abort) ;
    }
    va_end (args);
    if(abort){
      Debug();
      FinalizeAndExit();
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  P r o g r e s s                                                         */
/* ------------------------------------------------------------------------ */

void Progress(int current, int final, char *label){
  char sockmsg[100];
  static int ProgressIndex ;

  if(Current.RankCpu || !Flag_VERBOSE || !Flag_PROGRESS) return ;

  if(!current){
    ProgressIndex = 0;
    if(100/(double)final > Flag_PROGRESS) Flag_PROGRESS = 100/final+1 ;
  }
  if(100*current/(double)final >= ProgressIndex){
    if(Flag_SOCKET > 0){
      sprintf(sockmsg, "(%s%d %%)", label, ProgressIndex) ;
      Gmsh_SendString(Flag_SOCKET, GMSH_CLIENT_PROGRESS, sockmsg);
    }
    else
      fprintf(stderr, "(%s%d %%)     \r", label, ProgressIndex) ;
    ProgressIndex += Flag_PROGRESS ;
  }
  if(current >= final-1){
    if(Flag_SOCKET < 0) fprintf(stderr, "                        \r") ;
  }

}


/* ------------------------------------------------------------------------ */
/*  D e b u g                                                               */
/* ------------------------------------------------------------------------ */

void Debug(void){
  /* non-empty so that optimizing compilers don't get rid of it */
  fprintf(stderr, " ") ;
}


syntax highlighted by Code2HTML, v. 0.9.1