/**
 * @file alog_api.h
 *
 * @brief ALOG API definition.
 *
 **/
#ifndef _ALOG_API_H_
#define _ALOG_API_H_


#ifdef __cplusplus
extern "C" {
#endif


/**
 * @enum ALOG_LEVEL
 * @brief Predefined levels of priorities.
 */
typedef enum
{
    ALOG_FATAL =    0x00,    /**< critical conditions */
    ALOG_ERR,                /**< error conditions */
    ALOG_WARN,               /**< warning conditions */
    ALOG_INFO,               /**< informational */
    ALOG_DEBUG,              /**< debug-level messages */
    ALOG_TRACE,              /**< normal but significant condition */
    ALOG_TRACE1,             /**< normal but significant condition */
    ALOG_TRACE2,             /**< normal but significant condition */
    ALOG_TRACE3,             /**< normal but significant condition */
    ALOG_TRACE4              /**< normal but significant condition */
} ALOG_LEVEL;


/**
 * @name Names of predefined media and layout
 * @{
 */
#define ALOG_MEDIA_NAME_STREAM      "stream"
#define ALOG_MEDIA_NAME_STDOUT      "stdout"
#define ALOG_MEDIA_NAME_STDERR      "stderr"
#define ALOG_MEDIA_NAME_DUMP        "dump"
#define ALOG_MEDIA_NAME_NET         "net"
#define ALOG_LAYOUT_NAME_BASIC      "basic"
#define ALOG_LAYOUT_NAME_DEFAULT    "default"
#define ALOG_LAYOUT_NAME_SHORT      "short"
#define ALOG_LAYOUT_NAME_TIME       "time"
#define ALOG_LAYOUT_NAME_DETAIL     "detail"
/** @}*/


/** 
 * @enum ALOG_MEDIA
 * @brief List of supported media types.
 */
typedef enum
{
    ALOG_MEDIA_STREAM   = 0x01,     /**< stream is used to dump logging events */
    ALOG_MEDIA_CIRCULAR = 0x02,     /**< memory circular a rotating buffer in which logging events are written. */
    ALOG_MEDIA_NET      = 0x04      /**< socket UDP connection is used to pass logging events */
} ALOG_MEDIA;


/**
 * @enum ALOG_LAYOUT
 * @brief List of supported layout types.
 */
typedef enum
{
    ALOG_LAYOUT_PATTERN   = 0x01      /**< pattern message format */
} ALOG_LAYOUT;


/** 
 * @enum ALOG_RESPOND
 * @brief Customer is able to set respond function on entering pre/post message forming state. In this list
 *        possible responses are enumerated
 */
typedef enum
{
    ALOG_RESPOND_PRE   = 0x0,    /**< respond on pre-form state */
    ALOG_RESPOND_POST,           /**< respond on post-form */
    ALOG_RESPOND_MAX             /**< max number of supported responses (should start from 0 to max) */
} ALOG_RESPOND;


/**
 * @union _ALOG_OBJ_EXT
 * @brief Set additional parameters that allow to configure media or layout objects
 */
typedef union _ALOG_OBJ_EXT
{
    /* ALOG_MEDIA_STREAM parameters */
    struct
    {
        char*   file_name;              /**< file name that collect media information.
                                            It may contain the following format characters: 
                                            Format Description 
                                            %D date as DDMMYYYY 
                                            %T thread ID
                                            %H host name
                                            */
        int     cache;                  /**< sets the cache to be used for I/O operations with the specified 
                                             stream, which becomes a fully buffered stream, or alternatively, 
                                             if the argument for buffer is NULL, it disables buffering for 
                                             the stream, which becomes an unbuffered stream */
        char*   rotation;               /**< rotation scheme description; if the argument for buffer is NULL, 
                                             it disables rotation mechanizm. Format of the line is X:Y:Z
                                             X - 0, no rotation; 1, open rotation; 2, size rotation
                                             Y - number of backup files
                                             Z - treshold size value in case size rotation*/
    } stream;       

    /* ALOG_MEDIA_CIRCULAR parameters */
    struct
    {
        char*   file_name;              /**< file name that collect media information.
                                            It may contain the following format characters: 
                                            Format Description 
                                            %D date as DDMMYYYY 
                                            %T thread ID
                                            %H host name
                                            */
        int     size;                   /**< sets the size to be used for I/O operations with the specified 
                                             circular, buffer object */
    } circular;       

    /* ALOG_MEDIA_NET parameters */
    struct
    {
        char    ip[16];                 /**< server ip address */
        short   port;                   /**< server port */
        int     cache;                  /**< cache size */
    } socket;       

    /* ALOG_LAYOUT_PATTERN parameters */
    struct
    {
        char*   line;                   /**< pattern line. It may contain the following format characters: 
                                            Format Description 
                                            %t ticks 
                                            %s seconds 
                                            %u milliseconds
                                            %T thread ID
                                            %P priority level name 
                                            %p priority level in numeric form 
                                            %C category name
                                            %D formatted data message
                                            %F full file name
                                            %f base name
                                            %M function name
                                            %L line number
                                            %H host name
                                            */
    } pattern;       
} ALOG_OBJ_EXT;


/**
 * @struct _ALOG_OBJ
 * @brief Describes media or layout objects
 */
typedef struct _ALOG_OBJ
{
    const char*     name;               /**< media or layout name */
    int             id;                 /**< media or layout type id */
    ALOG_OBJ_EXT*   context;            /**< object (media or layout) type extended information */
} ALOG_OBJ;


/**
 * @struct _ALOG_FORM
 * @brief This type allows to define initial configuration.
 */
typedef struct _ALOG_FORM
{
    ALOG_LEVEL      top_level;          /**< top level of message priorites applying to all categories */
    int             stdcat_count;       /**< categories count recognized by number; it is possible to use
                                             number value from zero to field value as category identifier; 
                                             usually  category is defined by unique string value */
    ALOG_OBJ*       media_array;        /**< array with media description information
                                             where the latest element should be zero to
                                             demonstrate the end of data */
    ALOG_OBJ*       layout_array;       /**< array with layout description information
                                             where the latest element should be zero to
                                             demonstrate the end of data */
} ALOG_FORM;


/**
 * alog_init
 *
 * @brief
 *    The function is used to initialize internal object.
 *    This function should be called at least once before using any other function.
 *    Special structured data can be passed to set initial logging parameters.
 *    In case user defined configuartion is not passed logging sets default parameters.
 *
 * @param[in]    config         Initial configuartion.
 *
 * @retval zero - on success
 * @retval non-zero - on failure
 ***************************************************************************/
extern int alog_init( ALOG_FORM* config );


/**
 * alog_exit
 *
 * @brief
 *    The function is used as a destructor.
 *
 * @param none
 *
 * @retval zero - on success
 * @retval non-zero - on failure
 ***************************************************************************/
extern int alog_exit( void );


/**
 * alog_set_priority
 *
 * @brief
 *    Set priority threshold level for all system.
 *
 * @param[in]    priority       Threshold priority value.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_BAD_ARGUMENT - Invalid parameter is detected;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_set_priority( int priority );


/**
 * alog_flush
 *
 * @brief
 *    If the given object was open for writing and the last i/o operation was an output operation, 
 *    any unwritten data in the output buffer is written to the media.
 *    If the argument is a null pointer, all open media are flushed.
 *
 * @param[in]    name           Media name.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_UNSUPPORTED - Unsupported category;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_flush( const char* name );


/**
 * alog_create
 *
 * @brief
 *    Create new category and identify one with unique name.
 *
 * @param[in]    name           Category name.
 *
 * @retval zero - on success
 * @retval non-zero - on failure
 ***************************************************************************/
extern int alog_create( const char* name );


/**
 * alog_set_active
 *
 * @brief
 *    Switch the category to active or inactive state.
 *
 * @param[in]    name           Category name.
 * @param[in]    active         Enable(TRUE)/Disable(FALSE) this category.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_BAD_ARGUMENT - Invalid parameter is detected;
 * @retval ALOG_ERR_UNSUPPORTED - Unsupported category;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_set_active( const char* name,
                            int active );


/**
 * alog_set_level
 *
 * @brief
 *    Set priority threshold level for the category.
 *
 * @param[in]    name           Category name.
 * @param[in]    level          Threshold value.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_BAD_ARGUMENT - Invalid parameter is detected;
 * @retval ALOG_ERR_UNSUPPORTED - Unsupported category;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_set_level( const char* name,
                           int level );


/**
 * alog_check_level
 *
 * @brief
 *    Verify if defined level satisfy the priority threshold level of the category
 *    and general level of system.
 *
 * @param[in]    name           Category name.
 * @param[in]    level          Threshold value.
 *
 * @retval TRUE - on success
 * @retval FALSE - on failure
 ***************************************************************************/
extern int alog_check_level( const char* name,
                             int level );


/**
 * alog_add_capability
 *
 * @brief
 *    Append new capability (media and layout) to list of supported by the category.
 *
 * @param[in]    name           Category name.
 * @param[in]    media_name     Media name.
 * @param[in]    layout_name    Layout name.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_BAD_ARGUMENT - Invalid parameter is detected;
 * @retval ALOG_ERR_UNSUPPORTED - Unsupported capability;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_add_capability( const char* name,
                                const char* media_name,
                                const char* layout_name );


/**
 * alog_del_capability
 *
 * @brief
 *    Remove the capability (media and layout) from list of supported by the category.
 *
 * @param[in]    name           Category name.
 * @param[in]    media_name     Media name.
 * @param[in]    layout_name    Layout name.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_BAD_ARGUMENT - Invalid parameter is detected;
 * @retval ALOG_ERR_UNSUPPORTED - Unsupported capability;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_del_capability( const char* name,
                                const char* media_name,
                                const char* layout_name );


/**
 * alog_set_respond
 *
 * @brief
 *    Set customer response to form output message.
 *
 * @param[in]    name           Category name.
 * @param[in]    id             Respond identificator.
 * @param[in]    proc           Respond procedure.
 * @param[in]    context        Respond context.
 *
 * @retval zero - on success
 * @retval non-zero - on failure
 ***************************************************************************/
extern int alog_set_respond( const char* name,
                             ALOG_RESPOND id,
                             void (*proc)(char *, int, void *),
                             void *context);


/**
 * alog_send
 *
 * @brief
 *    Send information to the media.
 *
 * @param[in]    name           Category name.
 * @param[in]    priority       Information priority.
 * @param[in]    file_name      Name of file where call is located.
 * @param[in]    line_no        Line in the file where call is located.
 * @param[in]    func_name      Function name where call is located.
 *
 * @retval ALOG_ERR_NONE - Function executed successfully;
 * @retval ALOG_ERR_BAD_ARGUMENT - Invalid parameter is detected;
 * @retval ALOG_ERR_NO_MEMORY - Dynamic memory allocation error;
 * @retval ALOG_ERR_FATAL - The core logging object incorrect;
 ***************************************************************************/
extern int alog_send( const char* name, 
                      ALOG_LEVEL priority,
                      const char* file_name,
                      const int line_no,
                      const char* func_name,
                      const char* format,
                      ...);


/**
 * alog_fatal
 *
 * @brief
 *    Log a message with ALOG_FATAL priority.
 *
 * @param[in]    category       Category name.
 * @param[in]    format         Format specifier for the string to write to media.
 * @param[in]    ...            The arguments for format.
 *
 * @return @a none
 ***************************************************************************/
#define alog_fatal( category, format, ... ) \
    alog_send(category, ALOG_FATAL, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)


/**
 * alog_error
 *
 * @brief
 *    Log a message with ALOG_ERROR priority.
 *
 * @param[in]    category       Category name.
 * @param[in]    format         Format specifier for the string to write to media.
 * @param[in]    ...            The arguments for format.
 *
 * @return @a none
 ***************************************************************************/
#define alog_error( category, format, ... ) \
    alog_send(category, ALOG_ERR, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)


/**
 * alog_warn
 *
 * @brief
 *    Log a message with ALOG_WARN priority.
 *
 * @param[in]    category       Category name.
 * @param[in]    format         Format specifier for the string to write to media.
 * @param[in]    ...            The arguments for format.
 *
 * @return @a none
 ***************************************************************************/
#define alog_warn( category, format, ... ) \
    alog_send(category, ALOG_WARN, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)


/**
 * alog_info
 *
 * @brief
 *    Log a message with ALOG_INFO priority.
 *
 * @param[in]    category       Category name.
 * @param[in]    format         Format specifier for the string to write to media.
 * @param[in]    ...            The arguments for format.
 *
 * @return @a none
 ***************************************************************************/
#define alog_info( category, format, ... ) \
    alog_send(category, ALOG_INFO, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)


/**
 * alog_debug
 *
 * @brief
 *    Log a message with ALOG_DEBUG priority.
 *
 * @param[in]    category       Category name.
 * @param[in]    format         Format specifier for the string to write to media.
 * @param[in]    ...            The arguments for format.
 *
 * @return @a none
 ***************************************************************************/
#define alog_debug( category, format, ... ) \
    alog_send(category, ALOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)


/**
 * alog_trace
 *
 * @brief
 *    Log a message with ALOG_TRACE priority.
 *
 * @param[in]    category       Category name.
 * @param[in]    format         Format specifier for the string to write to media.
 * @param[in]    ...            The arguments for format.
 *
 * @return @a none
 ***************************************************************************/
#define alog_trace( category, format, ... ) \
    alog_send(category, ALOG_TRACE, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)

#define alog_trace1( category, format, ... ) \
    alog_send(category, ALOG_TRACE1, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)

#define alog_trace2( category, format, ... ) \
    alog_send(category, ALOG_TRACE2, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)

#define alog_trace3( category, format, ... ) \
    alog_send(category, ALOG_TRACE3, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)

#define alog_trace4( category, format, ... ) \
    alog_send(category, ALOG_TRACE4, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)


/**
 * alog_strerr
 *
 * @brief
 *    The function maps errnum to an error-message string, returning a pointer to the string.
 *
 * @param[in]    errcode         Error number.
 *
 * @retval pointer to error string message - on success
 * @retval NULL - on failure
 ***************************************************************************/
extern const char* alog_strerr( int errcode );


#ifdef __cplusplus
}
#endif


#endif /* _ALOG_API_H_ */

