#ifndef ENVIRONMENT_CACHE_CACHE_ONELEVEL_PARAMETERS_H
#define ENVIRONMENT_CACHE_CACHE_ONELEVEL_PARAMETERS_H

#include <iostream>
#include <sstream>
#include <math.h>

namespace environment {
namespace cache {
namespace cache_onelevel {

  class Parameters
  {
  public : uint32_t nb_port      ;
  public : uint32_t nb_line      ;
  public : uint32_t size_line    ;
  public : uint32_t size_word    ;
  public : uint32_t associativity;
  public : uint32_t hit_latence  ;
  public : uint32_t miss_penality;
    
  public : Parameters (uint32_t nb_port      ,
		       uint32_t nb_line      ,
		       uint32_t size_line    ,
		       uint32_t size_word    ,
		       uint32_t associativity,
		       uint32_t hit_latence  ,
		       uint32_t miss_penality)
    {
      this->nb_port       = nb_port      ;
      this->nb_line       = nb_line      ;
      this->size_line     = size_line    ;
      this->size_word     = size_word    ;
      this->associativity = associativity;
      this->hit_latence   = hit_latence  ;
      this->miss_penality = miss_penality;

      if ((nb_line * size_line * associativity) == 0)
	{
	  std::cerr << "{Cache_OneLevel} all parameter must be greater that 0" << std::endl;
	  exit(1);
	}
      if ((nb_line % associativity) != 0)
	{
	  std::cerr << "{Cache_OneLevel} nb_line must be a mutiple of associativity" << std::endl;
	  exit(1);
	}
      
      if ((double)nb_line    != ::pow(2,::log2(nb_line)))
	{
	  std::cerr << "{Cache_OneLevel} nb_line must be a mutiple of 2^n" << std::endl;
	  exit(1);
	}
      
      if ((double)size_line != ::pow(2,::log2(size_line)))
	{
	  std::cerr << "{Cache_OneLevel} size_line must be a mutiple of 2^n" << std::endl;
	  exit(1);
	}
      
      if ((double)size_word != ::pow(2,::log2(size_word)))
	{
	  std::cerr << "{Cache_OneLevel} size_word must be a mutiple of 2^n" << std::endl;
	  exit(1);
	}
    }

  public : std::string print (uint32_t depth)
    {
      std::string tab (depth,'\t');
      std::stringstream str;

      str << tab << "* Capacity              : " << (nb_line * size_line * size_word) << " bytes" << std::endl
	  << tab << "  * Nb line             : " << nb_line       << std::endl
	  << tab << "  * Size line           : " << size_line     << std::endl
	  << tab << "  * Size word (in byte) : " << size_word     << std::endl
	  << tab << "* Timing                : " << std::endl
	  << tab << "  * Hit  latence        : " << hit_latence   << std::endl
	  << tab << "  * Miss penality       : " << miss_penality << std::endl
	  << tab << "* Other                 : " << std::endl
	  << tab << "  * Associativity       : " << associativity << std::endl
	  << tab << "  * Nb port             : " << nb_port       << std::endl;

      if (associativity == 1)
	str << tab << "  * Cache Direct Map";
      else
	if (associativity == nb_line)
	  str << tab << "  * Cache Full Associative";
	else
	  str << tab << "  * Cache Semi Associative";
      return str.str();
    }
    
    
    friend std::ostream& operator<< (std::ostream& output, Parameters &x)
    {
      output << x.print(0);
      return output;
    }
  };

};
};
};
#endif
