/*
   Error protocolling functions
   ----------------------------

   Must be initilized with "init_error".

   Functions must begin with MAKRO: T_DEBUG_ENTRY("test",20)
   Where "test" is the name of the function and the number is
   a 'level'-number, possibly unique for module/function.
   With it a certain filtering of protocoll information can
   be achieved.

   Function must end with:
   T_DEBUG_LEAVE

   To enter a position information where the function is left use:
   T_DEBUG_FUNCTION_POSITION(1)
   number is the position number, position on entry is 0

   To enter the error type use:
   T_DEBUG_SET_THIS_FUNCTION_ERROR(HELP_WINDOW_ALLREADY_OPEN)
   These error ID's should be listed below in "error_texte"

   generell (error) information is controlled by
   e_verbose (T_INT), this is a global variable. Corresponding output
   is via printf().

   function_history (TRUE/FALSE) if true displays for
   each function entry its levels parents

   function_timing (T_TRUE/T_FALSE) if true outputs the time
   spent in the function (calculated via clock())

   protocol_variant, what type is the protocoll control using,
   ERROR_NUMBER_EXACT, only functions which have a number equal to
   'current_error_level' are protocolled
   ERROR_NUMBER_HIGHER, all functions with an error number higher than
   'current_error_level' are protocolled

   ERROR_SPECIFIC, everything is protocolled
   use like:
   ...
   protocol_variant=ERROR_SPECIFIC;
   some_function();
   protocol_variant=ERROR_NUMBER_EXACT;
   ...
   to protocoll everything which is done in function 'some_function()'

   current_error_level, this holds the number used above

   error levels currently used:
      module   I   number
      -------------------
      file     I     5
      keyboard I     7
      dosmem   I    10
      d_list   I    15
      l_level  I    20
      vesa     I    25
      pcx      I    30
      bild     I    35
      win_raw  I    40
      parser   I    45
      button   I    50
      tprint   I    55
      tdispatc I    60
      updatef  I    65
      request  I    70
      help     I    75
      edit     I    85
      tool     I   100
      main     I   500
*/

# ifdef __cplusplus
 extern "C" {
# endif

# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <string.h>
# include <i86.h>
# include "standard.h"
# include "keyboard.h"
# include "file.h"
# include "error.h"

T_INT e_verbose=E_VERBOSE_STANDARD;
T_INT tool_error=T_OK;
T_INT function_history=T_FALSE;
T_INT function_timing=T_FALSE;
T_INT function_level=0;
T_INT level_max=0;
T_INT protocol_variant=ERROR_NUMBER_EXACT; // or LOWER, defines the type of protocoll ERROR_NUMBER_EXACT, ERROR_NUMBER_HIGHER, ERROR_SPECIFIC
T_PCHAR error_function_string[FUNCTION_MAX_DEPTH];
clock_t start_time[FUNCTION_MAX_DEPTH];
clock_t end_time[FUNCTION_MAX_DEPTH];
T_INT error_level_this_function[FUNCTION_MAX_DEPTH];
T_INT error_function_position[FUNCTION_MAX_DEPTH];
T_INT error_this_function[FUNCTION_MAX_DEPTH];
T_CHAR error_protocoll_string[MAX_PROTOCOLL_LENGTH];
T_INT current_error_level=0; // show level higher or equal than this value

static T_INT return_video = 3;
static T_INT is_protokoll_new=T_TRUE;
static T_PCHAR _file_name="tool_log.txt";
static T_CHAR file_name[MAX_PATH_LEN];
static FILE *file_handle=NULL;
static time_t error_time;
static T_CHAR indents[80];

T_VOID  indent(T_VOID);

typedef struct
{
 T_PCHAR text;
 T_INT  id;
} TEXT_UND_ID;

#define END_MARKER -1
#define VGA_BIOS   0x10

TEXT_UND_ID error_texte[]=
{
 {"TOOL_INIT_ERROR"                  , TOOL_INIT_ERROR},
 {"TOOL_NO_VESA_MODE_ACTIVE"         , TOOL_NO_VESA_MODE_ACTIVE},

 {"FILE_OPEN_ERROR"                  , FILE_OPEN_ERROR},
 {"FILE_NOT_CLOSED"                  , FILE_NOT_CLOSED},
 {"FILE_REWIND_ERROR"                , FILE_REWIND_ERROR},
 {"FILE_FORWARD_ERROR"               , FILE_FORWARD_ERROR},
 {"FILE_NO_HANDLE"                   , FILE_NO_HANDLE},
 {"FILE_READ_ERROR"                  , FILE_READ_ERROR},
 {"FILE_DIRECTORY_ERROR"             , FILE_DIRECTORY_ERROR},

 {"VESA_NOT_INITIALIZED"             , VESA_NOT_INITIALIZED},
 {"VESA_MODE_NOT_FOUND"              , VESA_MODE_NOT_FOUND},
 {"VESA_NOTHING_DONE"                , VESA_NOTHING_DONE},
 {"VESA_DRIVER_ERROR"                , VESA_DRIVER_ERROR},
 {"VESA_NO_MOUSEDRIVER_FOUND"        , VESA_NO_MOUSEDRIVER_FOUND},
 {"VESA_NO_MOUSE_INSTALLED"          , VESA_NO_MOUSE_INSTALLED},
 {"VESA_MOUSE_POSITION_OUT_OF_SCREEN", VESA_MOUSE_POSITION_OUT_OF_SCREEN},
 {"VESA_NO_RECTANGLE"                , VESA_NO_RECTANGLE},
 {"VESA_NO_VESA_MODE_FOUND"          , VESA_NO_VESA_MODE_FOUND},
 {"VESA_FAILED_SET_BANKED"           , VESA_FAILED_SET_BANKED},
 {"VESA_UNKNOWN_VESA_ERROR"          , VESA_UNKNOWN_VESA_ERROR},
 {"VESA_NO_DOS_MEMORY"               , VESA_NO_DOS_MEMORY},
 {"VESA_NO_SVGALIB"                  , VESA_NO_SVGALIB},

 {"GENERIC_MEMORY_NOT_AVAILABLE"     , GENERIC_MEMORY_NOT_AVAILABLE},
 {"GENERIC_NO_BACKGROUND"            , GENERIC_NO_BACKGROUND},
 {"GENERIC_TEXT_TO_LONG"             , GENERIC_TEXT_TO_LONG},

 {"WINDOW_NOT_AVAILABLE"             , WINDOW_NOT_AVAILABLE},
 {"WINDOW_DOUBLE_ID"                 , WINDOW_DOUBLE_ID},
 {"WINDOW_NO_AREA_MEMORY"            , WINDOW_NO_AREA_MEMORY},
 {"WINDOW_OPEN_ERROR"                , WINDOW_OPEN_ERROR},
 {"WINDOW_NO_GRAPHICS_MODE_ACTIVE"   , WINDOW_NO_GRAPHICS_MODE_ACTIVE},

 {"BUTTON_NOT_PRESSED"               , BUTTON_NOT_PRESSED},
 {"BUTTON_DOUBLE_ID"                 , BUTTON_DOUBLE_ID},
 {"BUTTON_NOT_AVAILABLE"             , BUTTON_NOT_AVAILABLE},
 {"BUTTON_NO_MEM_BILD"               , BUTTON_NO_MEM_BILD},
 {"BUTTON_DEFAULT_BITMAPS_NOT_FOUND" , BUTTON_DEFAULT_BITMAPS_NOT_FOUND},
 {"BUTTON_LOAD_BITMAP_ERROR"         , BUTTON_LOAD_BITMAP_ERROR},
 {"NO_VALUE_FOR_CHECK_BUTTON"        , NO_VALUE_FOR_CHECK_BUTTON},

 {"LIST_ELEMENT_NOT_FOUND"           , LIST_ELEMENT_NOT_FOUND},

 {"PARSE_PARSE_ERROR"                , PARSE_PARSE_ERROR},
 {"PARSE_INTEGER_OVERFLOW"           , PARSE_INTEGER_OVERFLOW},
 {"PARSE_FILE_END"                   , PARSE_FILE_END},
 {"PARSE_PARSE_FILE_NOT_FOUND"       , PARSE_PARSE_FILE_NOT_FOUND},
 {"PARSE_NO_TYPE_FOUND"              , PARSE_NO_TYPE_FOUND},
 {"PARSE_NO_NUMBER"                  , PARSE_NO_NUMBER},
 {"PARSE_NO_STRING"                  , PARSE_NO_STRING},
 {"PARSE_NO_ASCII"                   , PARSE_NO_ASCII},
 {"PARSE_NO_FILE_OPEN"               , PARSE_NO_FILE_OPEN},
 {"PARSE_PRE_PROCESS_ERROR"          , PARSE_PRE_PROCESS_ERROR},
 {"PARSE_DEFINE_ERROR"               , PARSE_DEFINE_ERROR},

 {"PCX_FILE_END"                     , PCX_FILE_END},
 {"PCX_LINE_TO_LONG"                 , PCX_LINE_TO_LONG},

 {"HELP_WINDOW_NOT_OPEN"             , HELP_WINDOW_NOT_OPEN},
 {"HELP_WINDOW_ALLREADY_OPEN"        , HELP_WINDOW_ALLREADY_OPEN},
 {"HELP_FILE_NOT_FOUND"              , HELP_FILE_NOT_FOUND},
 {"HELP_WINDOW_NOT_OPENED"           , HELP_WINDOW_NOT_OPENED},
 {"HELP_BUTTON_CREATION_FAILED"      , HELP_BUTTON_CREATION_FAILED},
 {"HELP_BUTTON_CANT_FIND_MYSELF"     , HELP_BUTTON_CANT_FIND_MYSELF},
 {"HELP_BUTTON_NO_USER_FUNCTION"     , HELP_BUTTON_NO_USER_FUNCTION},

 {"KEY_NULL_POUNTER"                 , KEY_NULL_POUNTER},
 {"KEY_BAD_INDEX"                    , KEY_BAD_INDEX},
 {"KEY_BREAK"                        , KEY_BREAK},

 {"EDIT_WINDOW_WITH_DESTRUCTOR"      , EDIT_WINDOW_WITH_DESTRUCTOR},
 {"EDIT_WINDOW_NO_BUTTON_SPACE"      , EDIT_WINDOW_NO_BUTTON_SPACE},
 {"EDIT_BUTTON_CREATION_FAILED"      , EDIT_BUTTON_CREATION_FAILED},
 {"EDIT_NO_LOG_WINDOW"               , EDIT_NO_LOG_WINDOW},

 {"LIST_OBJECT_NOT_FOUND"            , LIST_OBJECT_NOT_FOUND},

 {"NO ERROR TEXT AVAILABLE"          , END_MARKER}
};
/* */
/*****************************************************/
/* */
T_VOID error_protokoll(T_PCHAR types, ...)
{
 T_SINT i,e_error;
 T_CHAR helper[MAX_PROTOCOLL_LENGTH];
 va_list argument;
 va_start( argument, types );
 e_error=vsprintf(error_protocoll_string,types,argument);
 va_end( argument );
 indent();
 for (i=0;i<strlen(error_protocoll_string);i++)
 {
  if (error_protocoll_string[i]=='\n')
  {
   strncpy(helper,error_protocoll_string,i+1);
   helper[i+1]=(T_CHAR) 0;
   strcat(helper,indents);
   strcat(helper,error_protocoll_string+i+1);
   strcpy(error_protocoll_string,helper);
  }
 }
 if (e_error<0)
 {
  printf("\nAn error occured decoding protokoll args: %s",error_protocoll_string);
  tool_exit(0);
 }
 if (protocol_variant==ERROR_NUMBER_HIGHER)
  if (current_error_level<=error_level_this_function[function_level-1])
   error_function_protokoll(FUNCTION_PROTOCOLL,0);
 if (protocol_variant==ERROR_NUMBER_EXACT)
  if (current_error_level==error_level_this_function[function_level-1])
   error_function_protokoll(FUNCTION_PROTOCOLL,0);
 if (protocol_variant==ERROR_SPECIFIC)
  error_function_protokoll(FUNCTION_PROTOCOLL,0);
 flushall();
}
/* */
/*****************************************************/
/* */
T_CHAR far *get_text_von_id(T_INT id,TEXT_UND_ID *text_und_id)
{
 T_INT i=0;
 while (text_und_id[i].id!=END_MARKER)
 {
  if (text_und_id[i].id==id)
   break;
  i++;
 }
 return text_und_id[i].text;
}
/* */
/*****************************************************/
/* */
T_VOID tool_exit(T_INT tool_error)
{
 union _REGS regs;
 regs.h.ah = 0x00;          // Set mode
 regs.h.al = return_video;  // Mode
 int386(VGA_BIOS, &regs, &regs);
 printf("\ntool_exit() invoked!!!");
#ifdef T_DEBUG_ALLOW
 if (!level_max)
 {
  printf("\nTool exit in function: \"%s\"",error_function_string[function_level]);
  printf("\nFunction position: %i ",error_function_position[function_level]);
 }
 else
  printf("\nTool exit in function: <level to high>");
#else
 printf("\nTo get more information, please compile with \n #define T_DEBUG_ALLOW");
#endif
 printf("\nError: %s",get_text_von_id(tool_error,error_texte));
 if (is_protokoll_new==T_TRUE)
 {
  if ((file_handle=fopen(file_name, "wt"))==NULL)
  {
   regs.h.ah = 0x00;          // Set mode
   regs.h.al = return_video;  // Mode
   int386(VGA_BIOS, &regs, &regs);
   fKBDrestore();
   printf("\nCouldn't open log file... (exiting)");
   exit (1);
  }
  error_time=time(NULL);
  fprintf(file_handle, "\n************** LOGDATE: %s", ctime(&error_time));
  fclose(file_handle);
  is_protokoll_new=T_FALSE;
 }
 if ((file_handle=fopen(file_name, "at"))!=NULL)
 {
  fprintf(file_handle,"\ntool_exit() invoked!!!");
#ifdef T_DEBUG_ALLOW
  if (!level_max)
  {
   fprintf(file_handle,"\nTool exit in function: \"%s\"",error_function_string[function_level]);
   fprintf(file_handle,"\nFunction position %i ",error_function_position[function_level]);
  }
  else
   fprintf(file_handle,"\nTool exit in function: <level to high>");
#else
  fprintf(file_handle,"\nTo get more information, please compile with \n #define T_DEBUG");
#endif
  fprintf(file_handle,"\nError: %s",get_text_von_id(tool_error,error_texte));
  fclose(file_handle);
 }
 else
 {
  union _REGS regs;
  regs.h.ah = 0x00;          // Set mode
  regs.h.al = return_video;  // Mode
  int386(VGA_BIOS, &regs, &regs);
  fKBDrestore();
  printf("\nCouldn't append log file (exiting)... (exiting)");
  exit (1);
 }
 fKBDrestore();
 exit(tool_error);
}
/* */
/*****************************************************/
/* */
T_VOID error_function_protokoll(T_INT wo, clock_t t)
{
 indent();
 if (is_protokoll_new==T_TRUE)
 {
  if ((file_handle=fopen(file_name, "wt"))==NULL)
  {
   union _REGS regs;
   regs.h.ah = 0x00;          // Set mode
   regs.h.al = return_video;  // Mode
   int386(VGA_BIOS, &regs, &regs);
   printf("\nCouldn't open log file... (exiting)");
   exit (1);
  }
  error_time=time(NULL);
  fprintf(file_handle, "\n************** LOGDATE: %s", ctime(&error_time));
  fclose(file_handle);
  is_protokoll_new=T_FALSE;
 }
 if ((file_handle=fopen(file_name, "at"))!=NULL)
 {
  if (wo==FUNCTION_ENTRY)
  {
   if (!level_max)
   {
    if (function_timing==T_TRUE)
     fprintf(file_handle,"\n%sEntering function clock():%i (depth:%i) %s",indents,clock(),function_level,error_function_string[function_level]);
    else
     fprintf(file_handle,"\n%sEntering function (depth:%i) %s",indents,function_level,error_function_string[function_level]);
    if (function_history==T_TRUE)
    {
     int i;
     for (i=0;i<function_level;i++)
     {
      fprintf(file_handle,"\n %sfrom function (depth:%i) %s",indents,i ,error_function_string[i]);
     }
    }
   }
   else
   {
    fprintf(file_handle,"\n%sEnter Function Level depth:%i ",indents, function_level);
    fprintf(file_handle,"\n%sEntering function: <level to high>",indents);
   }
  }
  if (wo==FUNCTION_LEAVE)
  {
   if (!level_max)
   {
    fprintf(file_handle,"\n%sLeaving function %s",indents,error_function_string[function_level]);
    fprintf(file_handle," (depth:%i), position %i", function_level,error_function_position[function_level]);
    if (error_this_function[function_level]!=0)
     fprintf(file_handle,", error: %s",get_text_von_id(error_this_function[function_level],error_texte));
    if (function_timing==T_TRUE)
     fprintf(file_handle,", clock():%i, ticks:%i == %fseconds",clock(),t,(((float)t)/CLOCKS_PER_SEC));
   }
   else
   {
    fprintf(file_handle,"\n%sLeaving function <level to high> (depth:%i) ",indents, function_level);
   }
  }
  if (wo==FUNCTION_PROTOCOLL)
  {
   if (!level_max)
   {
    if (function_timing==T_TRUE)
     fprintf(file_handle,"\n%sProtocoll in function %s clock():%i (depth:%i), position %i",indents,clock(),error_function_string[function_level-1],function_level-1,error_function_position[function_level-1]);
    else
     fprintf(file_handle,"\n%sProtocoll in function %s (depth:%i), position %i",indents,error_function_string[function_level-1],function_level-1,error_function_position[function_level-1]);
    fprintf(file_handle,"%s%s",indents,error_protocoll_string);
   }
   else
   {
    fprintf(file_handle,"\n%sProtocoll in function <level to high> (depth:%i), position %i",indents,function_level-1,error_function_position[function_level-1]);
    fprintf(file_handle,"%s%s",indents,error_protocoll_string);
   }
  }
  fclose(file_handle);
 }
 else
 {
  printf("\nCouldn't append log file (protocolling)... (exiting)");
  tool_exit(0);
 }
 flushall();
}
/* */
/*****************************************************/
/* */
T_VOID init_error(T_VOID)
{
 union _REGS regs;
 T_PCHAR path;
 regs.h.ah = 0x0f;          // Set mode
 int386(VGA_BIOS, &regs, &regs);
 return_video=regs.h.al;
 error_protocoll_string[0]=(T_CHAR)0;
 indents[0]=(T_CHAR)0;
 strcpy(file_name,_file_name);
 path=get_current_path();
 file_name[0]=0;
 strcat(file_name,path);
 free(path);
 strcat(file_name,"\\");
 strcat(file_name,_file_name);
}
/* */
/*****************************************************/
/* */
T_VOID t_printf(T_INT verbosity_level,T_PUCHAR pcString,...)
{
 va_list tGlop;
 /* Expand the varable argument list into the text buffer */
 /* Initialise the variable array */
 va_start(tGlop,pcString);
 if(vsprintf(error_protocoll_string,pcString,tGlop)==-1)
 {
  strcpy(error_protocoll_string,"t_printf() Text buffer overflow");
 }
 va_end(tGlop);
 if (e_verbose>=verbosity_level)
  printf("%s",error_protocoll_string);
 flushall();
}
/* */
/*****************************************************/
/* */
T_VOID indent(T_VOID)
{
 int i;
 indents[0]=0;
 for (i=0;i<function_level;i++)
 {
  if (strlen(indents)<79)
  {
   strcat(indents," ");
  }
 }
}
/* */
/*****************************************************/
/* */

# ifdef __cplusplus
 }
# endif


