#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef XVT
#define XVT_INCL_NATIVE
#define STRICT
#include <xvt.h>    

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
#include <keys.h>
#else
#include <xvtility.h>
#endif
#include <applicat.h>
#include <os_dep.h>
#endif /* XVT */


#include <checks.h>

#define buildmsg() char msg[256];va_list argptr;va_start(argptr,fmt);vsprintf(msg,fmt,argptr);va_end(argptr)

#ifndef FOXPRO

// @doc EXTERNAL

// @msg fatal_box | Crea una finestra di ERRORE FATALE con il relativo messaggio
bool fatal_box(
  const char* fmt, ...)  // @parm Messaggio da stampare nella finestra
  //       (il formato e' come nella printf del C)
  
  // @comm Se si opera in ambiente Windows crea la finestra con il bottone OK
  //       Il programma viene interrotto al momento in cui si e' verificato
  //       l'errore.
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBeep(MB_ICONHAND);
  MessageBox(GetFocus(), msg, "ERRORE FATALE", MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);

  if (xvt_running())
    main_app().stop_run();
  else
    exit(1);
#else
  beep();
  if (xvt_running()) xvt_dm_post_fatal_exit("%s", msg);
  else
  {
    fprintf(stderr, "%s\n", msg);
    getchar();
    exit(1);
  }
#endif

  return 0;
}

// @doc EXTERNAL

// @msg error_box | Crea una finestra di ERRORE con il relativo messaggio
bool error_box(
  const char* fmt,   // @parm Messaggio da stampare nella finestra
  ...)                           // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
  

  // @comm Se si opera in ambiente Windows crea la finestra con il bottone OK
  //       e l'icona punto esclamativo.
{
  buildmsg();                                                            

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBeep(MB_ICONEXCLAMATION);
  MessageBox(GetFocus(), msg, "ERRORE", MB_OK | MB_ICONEXCLAMATION);
#else
  beep();
  if (xvt_running()) xvt_dm_post_error("%s", msg);
  else
  {
    fprintf(stderr, "%s\n", msg);
    getchar();
  }
#endif

  return 0;
}

// @doc EXTERNAL

// @msg warning_box | Crea una finestra di ATTENZIONE con il relativo messaggio
bool warning_box(
  const char* fmt,   // @parm Messaggio da stampare nella finestra
  ...)               // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>

  // @comm Se si opera in ambiente Windows crea la finestra con il bottone OK
  //       e l'icona punto di domanda.
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBeep(MB_ICONQUESTION);
  MessageBox(GetFocus(), msg, "ATTENZIONE", MB_OK | MB_ICONQUESTION);
#else
  beep();
  xvt_dm_post_note("%s", msg);
#endif

  return 0;
}

// @doc EXTERNAL

// @msg message_box | Crea una finestra di INFORMAZIONE con relativo il messaggio
bool message_box(
  const char* fmt,  // @parm Messaggio da stampare nella finestra
  ...)                          // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
  
  // @comm Se si opera in ambiente Windows crea la finestra con il bottone OK
  //       e l'icona informazioni.
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBox(GetFocus(), msg, "INFORMAZIONE", MB_OK | MB_ICONINFORMATION);
#else
  xvt_dm_post_note("%s", msg);
#endif

  return 0;
}

// @doc EXTERNAL

// @msg sorry_box | Crea una finestra di SCUSE con il relativo messaggio
bool sorry_box(
  const char* fmt, // @parm Messaggio da stampare nella finestra
  ...)                     // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>

  // @comm Se si opera in ambiente Windows crea la finestra con il bottone OK
  //       e l'icona informazioni.
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBeep(MB_ICONINFORMATION);
  MessageBox(GetFocus(), msg, "SPIACENTE", MB_OK | MB_ICONINFORMATION);
#else
  xvt_dm_post_note("%s", msg);
#endif

  return 0;
}

// @doc EXTERNAL

// @msg yesno_box | Crea una finestra di RICHIESTA con il relativo messaggio
bool noyes_box(
  const char* fmt,   // @parm Messaggio da stampare nella finestra
  ...)               // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBeep(MB_ICONQUESTION);
  int r = MessageBox(GetFocus(), msg, "RICHIESTA",
                     MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2);
  return r == IDYES;
#else
  ASK_RESPONSE r = xvt_dm_post_ask((char*) "No", (char*) "Si", NULL, "%s", msg);
  if (r == RESP_DEFAULT) r = K_NO;
  else
    if (r == RESP_2) r = K_YES;
  return r == K_YES;
#endif
}


// @doc EXTERNAL

// @msg yesno_box | Crea una finestra di RICHIESTA con il relativo messaggio
bool yesno_box(
  const char* fmt,   // @parm Messaggio da stampare nella finestra
  ...)                           // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>


  // @comm Se si opera in ambiente Windows crea la finestra con i bottni SI e NO
  //       e l'icona col punto di domanda.
  //
  // @rdesc Ritorna il risultato della richiesta:
  // 
  // @flag 1 | Se viene premuto il taso SI
  // @flag 0 | Se viene premuto il taso NO
  //
  // @xref <m yesnocancel_box> <m yesnofatal_box>
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  MessageBeep(MB_ICONQUESTION);
  int r = MessageBox(GetFocus(), msg, "RICHIESTA", MB_YESNO | MB_ICONQUESTION);
  return r == IDYES;
#else
  ASK_RESPONSE r = xvt_dm_post_ask((char*) "Si", (char*) "No", NULL, "%s", msg);
  return r == RESP_DEFAULT;
#endif
}

// @doc EXTERNAL

// @msg yesnofatal_box | Crea una finestra di RICHIESTA con il relativo
//                        messaggio, ma permette di terminare il programma
bool yesnofatal_box(
  const char* fmt,   // @parm Messaggio da stampare nella finestra
  ...)                           // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>

  // @comm Se si opera in ambiente Windows crea la finestra con i bottoni SI e NO
  //       e l'icona col punto di domanda.
  //       <nl>A differenza della <m yesno_box> permette di terminare il programma
  //             se viene premuto il tasto SI
  //
  // @rdesc Ritorna il risultato della richiesta:
  // 
  // @flag 1 | Se viene premuto il tasto SI
  // @flag 0 | Se viene premuto il tasto NO
  //
  // @xref <m yesno_box> <m yesnofatal_box>
{
  buildmsg();

#ifdef DBG  
  char s[256]; sprintf(s, "%s\nContinuare ugualmente?", msg);
  const bool ret = yesno_box("%s", s);
  if (!ret) fatal_box(msg);
#else
  fatal_box("%s", msg);
#endif

  return FALSE;
}

// @doc EXTERNAL

// @msg yesnocancel_box | Crea una finestra di RICHIESTA con il relativo messaggio
int yesnocancel_box(
  const char* fmt,   // @parm Messaggio da stampare nella finestra
  ...)               // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>

  // @comm Se si opera in ambiente Windows crea la finestra con i bottoni SI e NO
  //       e l'icona col punto di domanda.
  //
  // @rdesc Ritorna il risultato della richiesta:
  // 
  // @flag K_YES | Se viene premuto il tasto SI
  // @flag K_NO | Se viene premuto il tasto NO
  // @flag K_ESC | Se viene premuto il tosto ESC
  //
  // @xref <m yesno_box> <m yesnofatal_box>
{
  buildmsg();

#if XVT_OS == XVT_OS_WIN || XVT_OS == XVT_OS_WIN32
  int r = MessageBox(GetFocus(), msg, "RICHIESTA", MB_YESNOCANCEL | MB_ICONQUESTION);
  if (r == IDYES) r = K_YES;
  else
    if (r == IDNO) r = K_NO;
    else
      r = K_ESC;
  return r;
#else
  ASK_RESPONSE r = xvt_dm_post_ask((char*) "Si", (char*) "No", (char*) "Annulla", "%s", msg);
  if (r == RESP_DEFAULT) r = K_YES;
  else
    if (r == RESP_2) r = K_NO;
    else
      r = K_ESC;
  return r;
#endif
}

// @doc EXTERNAL

// @msg __trace | Permette di mandare dei messaggi nel file trace.log
bool __trace(
  const char* fmt,   // @parm Messaggio da stampare
  ...)               // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>

  // @comm Usato in fase di debug, permette di vedere se il programma ha
  //             fatto certe operazioni (deve essere definito il simbolo TRC in
  //             fase di compilazione).
  //
  // @rdesc Ritorna non 0 se riesca ad aprire il file trace.log
{
  static FILE* f = NULL;
  if (f == NULL)
    f = fopen("trace.log", "w");
  if (f != NULL)
  {
    buildmsg();
    fprintf(f, "%s\n", msg);
    fflush(f);
  }
  return f != NULL;  
}

bool __tracemem(const char* msg)
{
  unsigned long mem = os_get_free_memory() / 1024;
  return __trace("%5lu Kb - %s", mem, msg);
}


#else   // FOXPRO

#include <windows.h>
#include <pro_ext.h>

bool error_box(const char* fmt, ...)
{
  buildmsg();
  MessageBeep(MB_ICONEXCLAMATION);
  _UserError(msg);
  return 0;
}

bool fatal_box(const char* fmt, ...)
{
  buildmsg();
  MessageBeep(MB_ICONHAND);
  MessageBox(GetFocus(), msg, "ERRORE FATALE", MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
  _UserError(msg);
  return 0;
}

bool message_box(const char* fmt, ...)
{
  buildmsg();
  MessageBeep(MB_ICONINFORMATION);
  _UserError(msg);
  return 0;
}

bool yesnofatal_box(const char* fmt, ...)
{
  buildmsg();
  MessageBeep(MB_ICONHAND);
  MessageBox(GetFocus(), msg, "ERRORE FATALE", MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
  _UserError(msg);
  return 0;
}
#endif // FOXPRO