#ifndef CACHE_H
#define CACHE_H

#include "Common/include/BitManipulation.h"
#include "Common/include/Debug.h"
#include "Common/include/Log2.h"
#include "Common/include/Test.h"
#include "Behavioural/include/Constants.h"
#include "Behavioural/include/Types.h"
#include <list>

//================================================================={Cache_t}

typedef int32_t cycle_t;

typedef struct 
{
  cycle_t                               _cycle     ;
  morpheo::behavioural::Tcontext_t      _context_id;
  morpheo::behavioural::Tpacket_t       _packet_id ;
  morpheo::behavioural::Tdcache_data_t  _rdata     ;
  morpheo::behavioural::Tdcache_error_t _error     ;
} cache_rsp_t;

class Cache_t
{
private : const uint32_t    _miss_rate;
private : const uint32_t    _miss_penality;
private : std::list<cache_rsp_t> _list_respons;
					 
public  : Cache_t (uint32_t miss_rate, uint32_t miss_penality):
  _miss_rate     (miss_rate    ),
  _miss_penality (miss_penality)
  {
//     srand(0);

    if (miss_rate > 100)
      throw morpheo::ErrorMorpheo(_("Miss_rate can be higher than 100"));
  }

public  : ~Cache_t (void)
  {
  }

public  : void push (morpheo::behavioural::Tcontext_t      context_id,
		     morpheo::behavioural::Tpacket_t       packet_id ,
		     morpheo::behavioural::Tdcache_data_t  rdata     ,
		     morpheo::behavioural::Tdcache_error_t error     )
  {
    cycle_t cycle = ((static_cast<uint32_t>(rand())%100)<_miss_rate)?_miss_penality:1;

    cache_rsp_t rsp;

    rsp._cycle      = cycle     ;
    rsp._context_id = context_id;
    rsp._packet_id  = packet_id ;
    rsp._rdata      = rdata     ;
    rsp._error      = error     ;

    // find good place
    std::list<cache_rsp_t>::iterator i;
    for(i = _list_respons.begin(); (i != _list_respons.end()) and (i->_cycle<=cycle); i++);

    _list_respons.insert(i,rsp);
  }

public  : void pop (void)
  {
    _list_respons.pop_front();
  }

public  : cache_rsp_t front (void)
  {
    return _list_respons.front();
  }

public  : bool have_rsp (void)
  {
    return (not _list_respons.empty()) and (_list_respons.front()._cycle <= 0);
  }

public  : void end_cycle (void)
  {
    for(std::list<cache_rsp_t>::iterator i = _list_respons.begin(); i != _list_respons.end(); i++)
      {
	i->_cycle --;
      }
  }

public  : void print (void)
  {
    for(std::list<cache_rsp_t>::iterator i = _list_respons.begin(); i != _list_respons.end(); i++)
      {
	std::cout << "{" << i->_cycle << "}\t" 
		  << i->_context_id << " - "
		  << i->_packet_id  << " - "
		  << i->_rdata      << " - "
		  << i->_error      << std::endl;
	  
      }
  }
};

inline void test_Cache_t (void)
{
  
  Cache_t * cache = new Cache_t (30,12);

  uint32_t cpt = 0;
  for (uint32_t i=0; i<10; i++)
    {
      for (uint32_t j=0; j<5; j++)
	cache->push(0,cpt++,0,0);

      for (uint32_t j=0; j<3; j++)
	if (cache->have_rsp())
	  {
	    std::cout << "pop : " << cache->front()._packet_id << std::endl;
	    cache->pop();
	  }
      cache->print();
      cache->end_cycle();
    }

  delete cache;
}

#endif
