// ****************************************************************************
//  Project:        libguytools
// ****************************************************************************
//  Programmer:     Guy Voncken
//                  Police Grand-Ducale
//                  Service de Police Judiciaire
//                  Section Nouvelles Technologies
// ****************************************************************************
//  Module:         Configuration utility
// ****************************************************************************

// Copyright 2008, 2009, 2010, 2011, 2012 Guy Voncken
//
// This file is part of libguytools.
//
// libguytools 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.
//
// libguytools 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 libguytools. If not, see <http://www.gnu.org/licenses/>.

#ifndef __TOOLCFG_H__
#define __TOOLCFG_H__

/* ------------------------------ */
/*  Type & structure definitions  */
/* ------------------------------ */

typedef enum
{
   CFGTYPE_PRESENCE,
   CFGTYPE_INTEGER,
   CFGTYPE_DOUBLE,
   CFGTYPE_STRING,
   CFGTYPE_SET,
   CFGTYPE_HMS,
   CFGTYPE_NULL
} t_ToolCfgType;


typedef enum
{
   CFGASN_SOURCE   = 0x0000000F,
   CFGASN_CMD      = 0x00000001,
   CFGASN_CFG      = 0x00000002,

   CFGASN_COUNT    = 0x000000F0,
   CFGASN_ONCE     = 0x00000010,
   CFGASN_TWICE    = 0x00000020,
   CFGASN_MULTIPLE = 0x00000030,

   CFGASN_OPTIONAL = 0x00000100
} t_ToolCfgAssignment;


#define CFGASSIGN_CMD              ((t_ToolCfgAssignment)(CFGASN_CMD | CFGASN_MULTIPLE                               ))
#define CFGASSIGN_CFG_ONCE         ((t_ToolCfgAssignment)(CFGASN_CFG | CFGASN_ONCE                                   ))
#define CFGASSIGN_CFG_MULTIPLE     ((t_ToolCfgAssignment)(CFGASN_CFG | CFGASN_MULTIPLE                               ))
#define CFGASSIGN_BOTH_ONCE        ((t_ToolCfgAssignment)(CFGASN_CMD | CFGASN_CFG | CFGASN_ONCE                      ))
#define CFGASSIGN_BOTH_TWICE       ((t_ToolCfgAssignment)(CFGASN_CMD | CFGASN_CFG | CFGASN_TWICE                     ))
#define CFGASSIGN_BOTH_MULTIPLE    ((t_ToolCfgAssignment)(CFGASN_CMD | CFGASN_CFG | CFGASN_MULTIPLE                  ))
#define CFGASSIGN_OPTIONAL         ((t_ToolCfgAssignment)(CFGASN_CMD | CFGASN_CFG | CFGASN_MULTIPLE | CFGASN_OPTIONAL))

typedef struct
{
   t_pcchar      pSetString;
   t_int          SetValue;
} t_ToolCfgSet, *t_pToolCfgSet;

typedef struct
{
   t_pcchar      pName;       /* The last one in the table must have pName set to NULL */
   t_ToolCfgType  CfgType;
   long           DestAddr;   /* For Params: the destination address: For table columns: the offset from the baseaddress */
   t_int          DestLen;    /* for strings, this length DOES NOT include the trailing '\0' */
   t_double       MinValue;
   t_double       MaxValue;
   t_pToolCfgSet pSetArray;
} t_ToolCfgDataDesc, *t_pToolCfgDataDesc;

/* ------------------------------------- */
/*  Structure to describe one parameter  */
/* ------------------------------------- */

typedef struct _t_ToolCfgParamDesc *t_pToolCfgParamDesc;

typedef APIRET (* t_pToolCfgCallOnInitFn)(t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText);

typedef struct  _t_ToolCfgParamDesc
{
   t_ToolCfgAssignment    Assign;
   t_pToolCfgCallOnInitFn pCallOnInitFn;
   t_ToolCfgDataDesc      DataDesc;

   /* The following two elements will be filled by the configuration scanner CfgScanConfiguration */
   /* and do not need to be set by the calling function.                                          */

   t_int            CmdAssignments;
   t_int            CfgAssignments;
} t_ToolCfgParamDesc;

#define CFG_FILLUP_FORLINT 0,0

/* ------------------------------- */
/*  Structure to describe a table  */
/* ------------------------------- */

typedef APIRET (* t_pTableStartFn      )(t_pchar pTableName, long *pBaseAddr, t_pcchar *ppErrorText);
typedef APIRET (* t_pTableSaveAndNextFn)(                    long *pBaseAddr, t_pcchar *ppErrorText);
typedef APIRET (* t_pTableEndFn        )(                                     t_pcchar *ppErrorText);

typedef struct
{
   t_pcchar              pTableType;
   t_pTableStartFn       pStartFn;
   t_pTableSaveAndNextFn pSaveAndNextFn;
   t_pTableEndFn         pEndFn;
   t_pToolCfgDataDesc    pDataDescArray; /* Pointer to array of data descriptors (one for each column) */
} t_ToolCfgTableDesc, *t_pToolCfgTableDesc;

/* Prototype of the user's logfunction */

typedef void (* t_pToolCfgUserLogFn)(t_pcchar pFileName, t_pcchar pFunction, t_int LineNr, t_pcchar pFormat, va_list pArguments);

/* ----------------- */
/*    Prototypes     */
/* ----------------- */

#ifdef __cplusplus
   #define EXTERN extern "C"
#elif __STDC__
   #define EXTERN extern
#else
   #error Unknown C compiler mode
#endif

EXTERN APIRET ToolCfgInit                   (int argc, char *argv[]);
EXTERN APIRET ToolCfgDeInit                 (void);
EXTERN APIRET ToolCfgUseAdjustedCommandLine (int argc, char *argv[]);
EXTERN APIRET ToolCfgSetLogFn               (t_pToolCfgUserLogFn pUserLogFn);
EXTERN APIRET ToolCfgGetCmdLineOption       (t_pcchar pParamName, t_pcchar *ppValue);
EXTERN APIRET ToolCfgAddGlobalSectionName   (t_pcchar pSectionName);
EXTERN APIRET ToolCfgDelGlobalSectionName   (t_pcchar pSectionName);
EXTERN APIRET ToolCfgScanConfiguration      (t_pcchar pFileName, t_pcchar pSectionName, t_ToolCfgParamDesc *pParamDescArray, t_ToolCfgTableDesc *pTableDescArray);
EXTERN APIRET ToolCfgBuildTemplate          (t_pcchar pFileName, t_pcchar pComment, t_pcchar pSectionName, t_ToolCfgParamDesc *pParamDescArray, t_ToolCfgTableDesc *pTableDescArray);
EXTERN APIRET ToolCfgLogConfiguration       (t_pToolCfgParamDesc pParamDescArray);
EXTERN APIRET ToolCfgPrintParamContents     (t_pToolCfgParamDesc pParamDescArray, t_pchar pName, t_pchar pBuff);
EXTERN APIRET ToolCfgGetSetString           (t_pToolCfgSet pSetArray, int SetValue, const char **ppSetString);

/* CfgGetCommandLineOption is usefull to the params that cannot be contained in the configuration file */
/* file itself, as for example the name of the cfg file.                                               */
/* Use CfgScanConfiguration to read a certain section of the cfg file. The two arrays pParamDescArray  */
/* and pTableDescArray specify the expected parameters and tables found in the indicated section.      */

/* ------------------------------ */
/*           Error codes          */
/* ------------------------------ */

static const APIRET TOOLCFG_ERROR_OPEN_FAILED               = ERROR_BASE_TOOL_CFG +  1;
static const APIRET TOOLCFG_ERROR_READ_FAILED               = ERROR_BASE_TOOL_CFG +  2;
static const APIRET TOOLCFG_ERROR_CLOSE_FAILED              = ERROR_BASE_TOOL_CFG +  3;
static const APIRET TOOLCFG_ERROR_FILE_NOT_FOUND            = ERROR_BASE_TOOL_CFG +  4;
static const APIRET TOOLCFG_ERROR_SEEKEND_FAILED            = ERROR_BASE_TOOL_CFG +  5;
static const APIRET TOOLCFG_ERROR_SEEKSET_FAILED            = ERROR_BASE_TOOL_CFG +  6;
static const APIRET TOOLCFG_ERROR_INVALID_STATE             = ERROR_BASE_TOOL_CFG +  7;
static const APIRET TOOLCFG_ERROR_NAME_TOO_LONG             = ERROR_BASE_TOOL_CFG +  8;
static const APIRET TOOLCFG_ERROR_INCLUDE_NESTING_OVERFLOW  = ERROR_BASE_TOOL_CFG +  9;
static const APIRET TOOLCFG_ERROR_CONFIG_ERROR              = ERROR_BASE_TOOL_CFG + 10;
static const APIRET TOOLCFG_ERROR_INVALID_ASSIGNMENT_OPTION = ERROR_BASE_TOOL_CFG + 11;
static const APIRET TOOLCFG_ERROR_INVALID_CFGTYPE           = ERROR_BASE_TOOL_CFG + 12;
static const APIRET TOOLCFG_ERROR_TEMPLATE_OPEN_FAILED      = ERROR_BASE_TOOL_CFG + 13;
static const APIRET TOOLCFG_ERROR_FPRINTF_FAILED            = ERROR_BASE_TOOL_CFG + 14;
static const APIRET TOOLCFG_ERROR_CMDLINE_OPTION_NOT_FOUND  = ERROR_BASE_TOOL_CFG + 15;
static const APIRET TOOLCFG_ERROR_SETBUF_FAILED             = ERROR_BASE_TOOL_CFG + 16;
static const APIRET TOOLCFG_ERROR_MALLOC_FAILED             = ERROR_BASE_TOOL_CFG + 17;
static const APIRET TOOLCFG_ERROR_SECTIONNAME_TOO_LONG      = ERROR_BASE_TOOL_CFG + 18;
static const APIRET TOOLCFG_ERROR_TOO_MANY_SECTIONNAMES     = ERROR_BASE_TOOL_CFG + 19;
static const APIRET TOOLCFG_ERROR_SECTIONNAME_NOTFOUND      = ERROR_BASE_TOOL_CFG + 20;
static const APIRET TOOLCFG_ERROR_UNKNOWN_PARAMETER         = ERROR_BASE_TOOL_CFG + 21;

#endif

