/** 
**************************************************************************
* @file mylibs_defs.h
* @brief Заголочный файл для дефайнов библиотеки MyLibsGeneral.
**************************************************************************
* @defgroup MYLIBS_DEFINES  My Libs defines
* @brief 		Базовые дефайны для всего проекта
*
*************************************************************************/
#ifndef __TRACKERS_H_
#define __TRACKERS_H_
#include "mylibs_defs.h"

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

    @verbatim
    typedef TrackerTypeDef(MEASURE_USER_VARS_NUMB) Measure_TrackerTypeDef;
    @endverbatim

    И через @ref Measure_TrackerTypeDef структура подключается в @ref TESTER_MeasureHandleTypeDef, а также
    если необхожимо в другие структуру, например в структуру всех ошибок через указатель @ref TESTER_TrackerTypeDef
    
	@{  
	*/

#ifdef TRACKERS_ENABLE
  /** 
    * @brief Структура для счетчиков отладки
    * @param num_user_vars - количество пользовательских счетчиков
    * @details Содержит счетчик для успешных событый (cnt_ok),
    * счетчик для ошибок (cnt_err), счетчик для предупреждений (cnt_warn).
    *
    * Также есть возможность объявить пользовательские счетчики в 
    * количестве <num_user_vars> штук.
    *
    * Для работы с структурой можно использовать функции:
    * - TrackerCnt_Ok()
    * - TrackerCnt_Err()
    * - TrackerCnt_Warn()
    * - TrackerCnt_User()
    * - TrackerWrite_User()
    * - TrackerClear_All()
    * - TrackerClear_Ok()
    * - TrackerClear_Err()
    * - TrackerClear_Warn()
    * - TrackerClear_User()
    * - TrackerClear_UserAll()
    */
  #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(_user_[0]))
  /** @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 Запись числа в пользовательскую переменную 
    * @note   Здесь нет проверки - существует ли пользовательская переменная! 
    *         Есть возможность выйти за границы структуры!!! 
    *         Чтобы этого избежать используете дефайн #ref assert_usertracker()
    */
  #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_)                               
  #define assert_tracecnt(_cntstruct_, _uservarnumb_)           

  #define TrackerCnt_Ok(_cntstruct_)                              
  #define TrackerCnt_Err(_cntstruct_)                             
  #define TrackerCnt_Warn(_cntstruct_)                            
  #define TrackerCnt_User(_cntstruct_, _uservarnumb_)                 
  #define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_)     

  /** @brief Очистка всей структуры */
  #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_