/*
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 *  SCR_Err.c
 *  Error managment.
 *
 *  Scripts, Beaudet Christophe
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 */
 
/*
 *=================================================================================================
 *  Includes.
 *=================================================================================================
 */
 
#include <setjmp.h>
#include <windows.h>
#include "SCR.h"
 
/*
 *=================================================================================================
 *  Global variables.
 *=================================================================================================
 */
 
/* 
 *  List of all errors.
 */
SCR_tdst_Err_Description g_a_st_Err_ListErrors[] =
{
    /* 
     *  Errors.
     */
#ifdef _DEBUG
    SCR_EI_Err_AssertionFailed,         "Assertion failed.",
#endif /* _DEBUG */
    SCR_EI_Err_EndSectionAlone,         "End section was found without associated beginning.",
    SCR_EI_Err_MissingEndSection,       "End of section was not found.",
    SCR_EI_Err_MissingEndSectionMark,   "End-Mark of section name is missing.",
    SCR_EI_Err_MissingEndFormatMark,    "Special character to indicate the end of format is missing.",
    SCR_EI_Err_MissingEndPostFormatMark,"Special character to indicate the end of post format is missing.",
    SCR_EI_Err_MissingEndStringMark,    "Special character to indicate the end of string is missing.",
    SCR_EI_Err_MissingEndParamsMark,    "Special character to indicate the end of list of parameters is missing.",
    SCR_EI_Err_MissingEndVarMark,       "Special character to indicate the end of variable is missing.",
    SCR_EI_Err_MissingParameters,       "List of parameters is missing.",
    SCR_EI_Err_MissingDirectiveName,    "Found directive special character without directive name.",
    SCR_EI_Err_CorruptEndOfLine,        "End of line is not correct, attempt for a return or eof.",
    SCR_EI_Err_ReadFile,                "Error while reading a file.",
    SCR_EI_Err_OpenFile,                "Unable to open file.",
    SCR_EI_Err_CloseFile,               "Unable to close file.",
    SCR_EI_Err_WriteFile,               "Unable to write to file.",
    SCR_EI_Err_CreatePath,              "Unable to create path",
    SCR_EI_Err_NotEnoughMemory,         "Not enough memory.",
    SCR_EI_Err_AlreadyRegistered,       "Section already registered.",
    SCR_EI_Err_UnknownSection,          "Unknown section searched.",
    SCR_EI_Err_UnknownDirective,        "Unknown directive.",
    SCR_EI_Err_UnknownVariable,         "Unknown variable.",
    SCR_EI_Err_UnknownFormat,           "Unknown format.",
    SCR_EI_Err_BadCharacter,            "Bad character read.",
    SCR_EI_Err_BadNumParamsAR,          "Bad number of parameters for array of references.",
    SCR_EI_Err_BadNumParamsScanf,       "Bad number of parameters for scanf format.",
    SCR_EI_Err_UnknownDynamicFlag,      "Unknown dynamic flag for automatic reference.",
    SCR_EI_Err_CantConvertScanfFormat,  "Can't convert a parameter with a scanf type format.",
 
    /* 
     *  Warnings.
     */
    SCR_EI_Err_UnnecessaryDirective,    "Unnecessary directive, ignored.",
    SCR_EI_Err_SectionWithoutCallback,  "Section without callback, ignored.",
 
	/*
	 *	Others...
	 */
    SCR_EI_Err_BadFileName,				"Bad file name for a CD.",		/* Fatal error */
};
 
/*
 *  To raise an error, and callback.
 */
SCR_tdst_Err_GlobalError    g_st_Err_GlobalError;
SCR_tdst_Err_Context        g_a_st_Err_Context[SCR_CV_ui_Cfg_MaxErrContext];
int                         g_i_Err_CurrentContext;
SCR_tdpfn_Err_Callback      SCR_g_pfn_Err_Callback;
unsigned short              SCR_g_uw_Err_Mode;
int							g_i_Err_GlobalReturn;
 
/*
 *  Name of log file when init error module.
 */
static char                 gs_a_szInitLogName[_MAX_PATH];
 
/*
 *=================================================================================================
 *  Functions.
 *=================================================================================================
 */
 
/*
 *-------------------------------------------------------------------------------------------------
 *  Init.
 *-------------------------------------------------------------------------------------------------
 */
void fn_v_Err_InitModule(void)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    FILE	*p_xFile;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	/*
     *  Delete "SCR_Err.log" file.
     *  Compute in gs_a_szInitLogName the full path to access log file (just in case
     *  of a chdir call in a load).
     */
	gs_a_szInitLogName[0] = '\0';
	p_xFile = fopen(SCR_CL_sz_Cfg_LogFileName, "wt");
    if(p_xFile)
    {
        if(_fullpath(gs_a_szInitLogName, SCR_CL_sz_Cfg_LogFileName, _MAX_PATH) == NULL)
            strcat(gs_a_szInitLogName, SCR_CL_sz_Cfg_LogFileName);
        fclose(p_xFile);
		unlink(gs_a_szInitLogName);
    }
	else
		unlink(SCR_CL_sz_Cfg_LogFileName);
 
    /*
     *  No global error callback.
     *  Current error context is -1 (none).
     *  Clear error.
     */
    SCR_g_pfn_Err_Callback = NULL;
    SCR_g_uw_Err_Mode = SCR_CM_Err_Normal;
    g_i_Err_CurrentContext = -1;
    SCR_fn_v_RdL0_ClearError();
}
 
/*
 *-------------------------------------------------------------------------------------------------
 *  Close.
 *-------------------------------------------------------------------------------------------------
 */
void fn_v_Err_CloseModule(void)
{
}
 
/*===============================================================================================*/
 
/*
 *-------------------------------------------------------------------------------------------------
 *  To initialize g_st_Err_GlobalError structure.
 *  eErrorId, p_szFileName, iLineInFile and a_szBufferTmp must be correct.
 *-------------------------------------------------------------------------------------------------
 */
void fn_v_Err_InitGlobalError(void)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    unsigned int    uiIndex;
    char            a_szTemp[SCR_CV_ui_Cfg_MaxLenError];
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    /*
     *  Get error structure associated to eErrorId (to obtain info string).
     */
    uiIndex = 0;
    while(g_a_st_Err_ListErrors[uiIndex].eErrorId != g_st_Err_GlobalError.eErrorId)
        uiIndex++;
 
    /* Info string */
    strcpy
    (
        g_st_Err_GlobalError.a_szBufferOut, 
        g_a_st_Err_ListErrors[uiIndex].p_szInfoString
    );
    strcat(g_st_Err_GlobalError.a_szBufferOut, "\n");
 
    /* Informations about source file */
    sprintf
    (
        a_szTemp,
        "Error was raised in source file \"%s\" at line \"%d\".\n",
        g_st_Err_GlobalError.p_szFileName,
        g_st_Err_GlobalError.iLineInFile
    );
    strcat(g_st_Err_GlobalError.a_szBufferOut, a_szTemp);
 
    /* Separator */
    if((*g_st_Err_GlobalError.a_szBufferTmp1) || (*g_st_Err_GlobalError.a_szBufferTmp1))
        strcat(g_st_Err_GlobalError.a_szBufferOut, "----------\n");
 
    /* Additional info string 1 */
    strcat(g_st_Err_GlobalError.a_szBufferOut, g_st_Err_GlobalError.a_szBufferTmp1);
 
    /* Additional info string 2 */
    strcat(g_st_Err_GlobalError.a_szBufferOut, g_st_Err_GlobalError.a_szBufferTmp2);
}
 
/*
 *-------------------------------------------------------------------------------------------------
 *  To raise an error.
 *-------------------------------------------------------------------------------------------------
 */
void fn_v_Err_SetError(void)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifdef _DEBUG
	FILE						*p_xFile;
	SCR_tdst_Cxt_Description	*p_stContext;
	int							iCpt;
#endif /* _DEBUG */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    /*
     *  Initialize global error.
     */
    fn_v_Err_InitGlobalError();
 
#ifdef _DEBUG
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    fn_v_Err_UpdateLogFile();
    if((SCR_g_uw_Err_Mode & SCR_CM_Err_NotUpdateLog) == 0)
    {
		if(*gs_a_szInitLogName)
		{
			p_xFile = fopen(gs_a_szInitLogName, "at");
			if(p_xFile == NULL)
				p_xFile = fopen(gs_a_szInitLogName, "wt");
			if(p_xFile)
			{
				iCpt = SCR_g_st_Cxt_Array.uiNumValues;
				while(iCpt)
				{
					fprintf(p_xFile, "\n<** Context %d **>\n", iCpt - SCR_g_st_Cxt_Array.uiNumValues);
					p_stContext = fnp_st_Cxt_Compute(iCpt - SCR_g_st_Cxt_Array.uiNumValues);
					if(p_stContext->p_stOpenFile)
						fprintf(p_xFile, "File     : %s\n", p_stContext->p_stOpenFile->stFile.a_szOpenFileName);
					if(p_stContext->p_stSectionDes)
						fprintf(p_xFile, "Section  : %s\n", p_stContext->p_stSectionDes->stBuffers.p_szBufferCompleteName);
					else if(p_stContext->p_stOpenFile)
						fprintf(p_xFile, "Section  : %s\n", p_stContext->p_stOpenFile->stFile.a_szOpenFileName);
					iCpt--;
				}
				fclose(p_xFile);
			}
		}
    }
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#endif /* _DEBUG */
 
    /*
     *  If there's an error callback, call it and restore context to return script parser.
     */
    if(SCR_g_pfn_Err_Callback)
    {
        SCR_g_pfn_Err_Callback(&g_st_Err_GlobalError);
        SCR_M_Err_RestoreContext();
    }
 
    /*
     *  Display the message.
     */
    g_i_Err_GlobalReturn = fn_i_Err_DisplayError
    (
        "Fatal error - Script parser aborted",
        g_st_Err_GlobalError.a_szBufferOut
    );
	switch(g_i_Err_GlobalReturn)
	{
	case IDRETRY:
		return;
	default:
		break;
	}
 
    /*
     *  Stop parser.
     *  The file whose name if define with SCR_C_sz_Cfg_LogFileName (constant in "SCR_Cfg.h") 
     *  contains the same informations that the previous dialog box.
     *
     *  Good luck to find the error !!!
     */
    SCR_M_Dbg_BreakForDebug();
    exit(0);
}
 
/*
 *-------------------------------------------------------------------------------------------------
 *  To raise a warning.
 *-------------------------------------------------------------------------------------------------
 */
void fn_v_Err_SetWarning(void)
{
    /*
     *  Initialize global error.
     */
    fn_v_Err_InitGlobalError();
 
    /*
     *  Update .log file.
     */
    fn_v_Err_UpdateLogFile();
 
    /*
     *  Clear error (cause it's a warning).
     */
    SCR_fn_v_RdL0_ClearError();
}
 
/*===============================================================================================*/
 
/*
 *-------------------------------------------------------------------------------------------------
 *  To update log file.
 *-------------------------------------------------------------------------------------------------
 */
void fn_v_Err_UpdateLogFile(void)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	FILE						*p_xFile;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if((SCR_g_uw_Err_Mode & SCR_CM_Err_NotUpdateLog) == 0)
    {
		if(*gs_a_szInitLogName)
		{
			p_xFile = fopen(gs_a_szInitLogName, "at");
			if(p_xFile == NULL)
				p_xFile = fopen(gs_a_szInitLogName, "wt");
			if(p_xFile)
			{
				fprintf(p_xFile, "%s", g_st_Err_GlobalError.a_szBufferOut);
				fprintf(p_xFile, "\n----------------(:-)----------------\n\n");
				fclose(p_xFile);
			}
		}
    }
}
 
/*
 *-------------------------------------------------------------------------------------------------
 *  To say to user that a fatal error occured.
 *  _Type   :   A string to indicate the type of error.
 *  _Info   :   A string that describes the error.
 *-------------------------------------------------------------------------------------------------
 */
int fn_i_Err_DisplayError(char *_p_szType, char *_p_szInfo)
{
	unsigned int	uiStyle;
 
    if((SCR_g_uw_Err_Mode & SCR_CM_Err_NotDisplayInfos) == 0)
    {
		/* Change message box style depending on error */
		switch(g_st_Err_GlobalError.eErrorId)
		{
		case SCR_EI_Err_OpenFile:
			uiStyle = MB_RETRYCANCEL|MB_ICONERROR;
			break;
		default:
			uiStyle = MB_OK|MB_ICONERROR;
			break;
		}
 
		/* Display message box */
        return Erm_fn_iMessageBox
        (
            _p_szInfo,
            _p_szType,
            uiStyle
        );
    }
}
