/** 
**************************************************************************
* @file trackers.h
* @brief Заголочный файл для работы с трекерами @ref TRACKERS.
**************************************************************************
* @addtogroup TRACKERS        Trackers defines
* @ingroup    MYLIBS_DEFINES
* @brief      Дефайны для работы с трекерами
* @details    
Есть дефайн для объявления структуры трекера: TrackerTypeDef(num_user_vars). 
Структура состоит из следующих элементов: 
- cnt_ok
- cnt_err
- cnt_warn
- user[num_user_vars]    
Также есть ряд функций (дефайнов) для обращения к элементам этой структуры.

Параметры для конфигурации:
- @ref TRACKERS_ENABLE - Включить трекеры
  Если трекеры @ref TRACKERS_ENABLE отключены, то все дефайны определяются как ничего 
  и на производительность кода не влияют  

@par Пример:

Определяем typedef трекера измерений Measure_TrackerTypeDef

@verbatim
  typedef TrackerTypeDef(MEASURE_USER_VARS_NUMB) Measure_TrackerTypeDef;
@endverbatim

И через @ref Measure_TrackerTypeDef структура подключается в другие структуры

Для работы с структурой можно использовать функции:
- Для получения значения:
  - TrackerGet_Ok()
  - TrackerGet_Err()
  - TrackerGet_Warn()
  - TrackerGet_User(n)
  
- Для записи значения:
  - TrackerCnt_Ok()
  - TrackerCnt_Err()
  - TrackerCnt_Warn()
  - TrackerCnt_User()
  - TrackerWrite_User(n)
  
- Для очищения значения:
  - TrackerClear_All()
  - TrackerClear_Ok()
  - TrackerClear_Err()
  - TrackerClear_Warn()
  - TrackerClear_User(n)
  - TrackerClear_UserAll()
* @{  
*************************************************************************/
#ifndef __TRACKERS_H_
#define __TRACKERS_H_
#include "mylibs_defs.h"

#ifdef TRACKERS_ENABLE
  /** 
    * @brief Структура для счетчиков отладки
    * @param num_user_vars - количество пользовательских переменных
    * @details Содержит счетчик для успешных событый (cnt_ok),
    * счетчик для ошибок (cnt_err), счетчик для предупреждений (cnt_warn).
    *
    * Также есть возможность объявить пользовательские переменные в 
    * количестве <num_user_vars> штук.
    */
  #define TrackerTypeDef(num_user_vars)       \
  struct                                      \
  {                                           \
    uint32_t cnt_ok;                          \
    uint32_t cnt_err;                         \
    uint32_t cnt_warn;                        \
    uint32_t user[num_user_vars];             \
  }

  /** @brief Получить количетство пользовательских переменных */
  #define num_of_usercnts(_user_)                               (sizeof(_user_) / sizeof(uint32_t))
  /** @brief Проверка существует ли указанная пользовательская переменная */
  #define assert_usertracker(_cntstruct_, _uservarnumb_)        ((_uservarnumb_) < num_of_usercnts((_cntstruct_).user))
  /** @brief Условие для проверки существует ли указанная пользовательская переменная */
  #define if_assert_usertracker(_cntstruct_, _uservarnumb_)     if(assert_usertracker(_cntstruct_, _uservarnumb_))
  /** @brief Тернарный оператор для проверки существует ли указанная пользовательская переменная */
  #define tern_assert_usertracker(_cntstruct_, _uservarnumb_)   (assert_usertracker(_cntstruct_, _uservarnumb_)) ? _uservarnumb_ : 0

  
  /** @brief Считать счетчик успешных событий */
  #define TrackerGet_Ok(_cntstruct_)                              (_cntstruct_).cnt_ok
  /** @brief Считать счетчик ошибок */
  #define TrackerGet_Err(_cntstruct_)                             (_cntstruct_).cnt_err
  /** @brief Считать счетчик предупреждений */
  #define TrackerGet_Warn(_cntstruct_)                            (_cntstruct_).cnt_warn
  /** 
    * @brief Считать пользовательскую переменную 
    * @note   Здесь нет проверки - существует ли пользовательская переменная! 
    *         Есть возможность выйти за границы структуры!!! 
    *         Чтобы этого избежать можно использовать дефайн #ref assert_usertracker()
    @verbatim   
      if(assert_usertracker(struct, 0)) {
          TrackerGet_User(struct, 0)
      }
    @endverbatim
    */
  #define TrackerGet_User(_cntstruct_, _uservarnumb_)             (_cntstruct_).user[tern_assert_usertracker(_cntstruct_, _uservarnumb_)]
  
  
  
  /** @brief Инкрементирование счетчика успешных событий */
  #define TrackerCnt_Ok(_cntstruct_)                              (_cntstruct_).cnt_ok++
  /** @brief Инкрементирование счетчика ошибок */
  #define TrackerCnt_Err(_cntstruct_)                             (_cntstruct_).cnt_err++
  /** @brief Инкрементирование счетчика предупреждений */
  #define TrackerCnt_Warn(_cntstruct_)                            (_cntstruct_).cnt_warn++
  /** @brief Инкрементирование пользовательской переменной */
  #define TrackerCnt_User(_cntstruct_, _uservarnumb_)             if_assert_usertracker(_cntstruct_, _uservarnumb_) (_cntstruct_).user[_uservarnumb_]++;
  /** @brief Запись числа в пользовательскую переменную */
  #define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_)    if_assert_usertracker(_cntstruct_, _uservarnumb_) (_cntstruct_).user[_uservarnumb_] = (_val_)

  /** @brief Очистка всей структуры */
  #define TrackerClear_All(_cntstruct_)                           memset(&(_cntstruct_), 0, sizeof(_cntstruct_))
  /** @brief Очистка счетчика успешных событий */
  #define TrackerClear_Ok(_cntstruct_)                            (_cntstruct_).cnt_ok = 0
  /** @brief Очистка счетчика ошибок */
  #define TrackerClear_Err(_cntstruct_)                           (_cntstruct_).cnt_err = 0
  /** @brief Очистка счетчика предупреждений */
  #define TrackerClear_Warn(_cntstruct_)                          (_cntstruct_).cnt_warn = 0
  /** @brief Очистка пользовательской переменной */
  #define TrackerClear_User(_cntstruct_, _uservarnumb_)           if_assert_usertracker(_cntstruct_, _uservarnumb_) (_cntstruct_).user[_uservarnumb_] = 0;
  /** @brief Очистка всех пользовательских переменных */
  #define TrackerClear_UserAll(_cntstruct_)                       memset(&(_cntstruct_).user, 0, sizeof((_cntstruct_).user))

#else //TRACKERS_ENABLE
  
  #define TrackerTypeDef(num_user_vars) void *

  #define num_of_usercnts(_user_)                               0
  #define assert_tracecnt(_cntstruct_, _uservarnumb_)           0
  #define if_assert_usertracker(_cntstruct_, _uservarnumb_)     if(0)
  #define tern_assert_usertracker(_cntstruct_, _uservarnumb_)   0

  #define TrackerGet_Ok(_cntstruct_)                            dummy
  #define TrackerGet_Err(_cntstruct_)                           dummy
  #define TrackerGet_Warn(_cntstruct_)                          dummy 
  #define TrackerGet_User(_cntstruct_, _uservarnumb_)           dummy
  
  #define TrackerCnt_Ok(_cntstruct_)                              
  #define TrackerCnt_Err(_cntstruct_)                             
  #define TrackerCnt_Warn(_cntstruct_)                            
  #define TrackerCnt_User(_cntstruct_, _uservarnumb_)                 
  #define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_)

  #define TrackerClear_All(_cntstruct_)                        
  #define TrackerClear_Ok(_cntstruct_)                         
  #define TrackerClear_Err(_cntstruct_)                        
  #define TrackerClear_Warn(_cntstruct_)                       
  #define TrackerClear_User(_cntstruct_)                       
  #define TrackerClear_UserAll(_cntstruct_)                    

#endif //TRACKERS_ENABLE
  
#endif //__TRACKERS_H_