#ifndef __SEC_STATS_H
#define __SEC_STATS_H

/**
  macro to start a cycle counter, param is the name (x) of the counter
 */
#define S_START(x)				\
  do						\
  {						\
    Stats *stats = Stats::getStats();		\
    stats->start(x);				\
  } while (0)

/**
  macro to stop a cycle counter, param is the name (x) of the counter
 */
#define S_STOP(x)				\
  do						\
  {						\
    Stats *stats = Stats::getStats();		\
    stats->stop(x);				\
  } while (0)

/**
  macro to print the value of the cycle counter given by the name (x), with a message (msg)
 */
#define S_PRINT(x, msg)				\
  do						\
  {						\
    Stats *stats = Stats::getStats();		\
    stats->print(x, msg);			\
  } while (0)

/**
  macro to update the value of the general cycle counter, as to be used by the main FSM
 */
#define S_UPDATE()				\
  do						\
  {						\
    Stats *stats = Stats::getStats();		\
    stats->update();				\
  } while (0)

#include <map>
#include "debug.h"

class Stats
{
private:
  Stats()
  {
    counter = 0;
    _my_stat = std::map<const char *, uint64_t>();
  }

  ~Stats()
  {
  }

  static Stats *_stats;
  std::map<const char *, uint64_t> _my_stat;
  uint64_t counter;

public:
  static Stats *getStats()
  {
    if (_stats== NULL)
      _stats = new Stats();

    return _stats;
  }
  
  static void destroy()
  {
    if (_stats != NULL)
      delete _stats;
  }

  void update()
  {
    counter++;
  }

  void start(const char *name)
  {
    if (_my_stat.find(name) != _my_stat.end())
    {
      if ((_my_stat[name] & (1ULL<<63)) == 0)
      {
	fprintf(stderr, "[STATS] reset counter for %s\n", name);
      }
      _my_stat[name] = counter;
    }
    else
    {
      _my_stat.insert(std::pair<const char *, uint64_t>(name, counter));
    }
  }

  void stop(const char *name)
  {
    if (_my_stat.find(name) == _my_stat.end())
    {
      fprintf(stderr, "[STATS] cannot find counter %s\n", name);
    }
    else
    {
      // we use the msb as stop bit
      // counter already stop
      if (_my_stat[name] & (1ULL<<63))
	fprintf(stderr, "[STATS] try to stop an already stopped counter (%s)\n", name);
      else
	_my_stat[name] = (1ULL<<63) | (counter - _my_stat[name]);
    }
  }

  void print(const char *name, const char *msg)
  {
    std::map<const char *, uint64_t>::iterator it;
    if ((it = _my_stat.find(name)) == _my_stat.end())
    {
      fprintf(stderr, "[STATS] cannot find counter %s\n", name);
    }
    else
    {
      // counter is stop, print only the 63 lsb
      if (it->second & (1ULL<<63))
	DEBUG(NONE, STD, "[%s] %lu %s\n", it->first, (it->second&(~(1ULL<<63))), msg);
      else
	DEBUG(NONE, STD, "[%s] %lu %s\n", it->first, counter - it->second, msg);
    }
  }
};

Stats *Stats::_stats = NULL;

#endif
