#ifndef ENVIRONMENT_CACHE_PARAMETERS_H
#define ENVIRONMENT_CACHE_PARAMETERS_H

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

#include "Cache_MultiLevel_Parameters.h"

namespace environment {
namespace cache {

  class Parameters
  {
  public : uint32_t nb_cache_dedicated;
  public : uint32_t nb_iport;
  public : uint32_t nb_dport;

  public : cache_multilevel::Parameters ** param_icache_dedicated;
  public : cache_multilevel::Parameters ** param_dcache_dedicated;
  public : cache_multilevel::Parameters  * param_cache_shared;
    
  public : Parameters (uint32_t    nb_cache_dedicated            ,
		       uint32_t  * icache_dedicated_nb_level     ,
		       uint32_t  * icache_dedicated_nb_port      ,
		       uint32_t ** icache_dedicated_nb_line      ,
		       uint32_t ** icache_dedicated_size_line    ,
		       uint32_t ** icache_dedicated_size_word    ,
		       uint32_t ** icache_dedicated_associativity,
		       uint32_t ** icache_dedicated_hit_latence  ,
		       uint32_t ** icache_dedicated_miss_penality,
		       uint32_t  * dcache_dedicated_nb_level     ,
		       uint32_t  * dcache_dedicated_nb_port      ,
		       uint32_t ** dcache_dedicated_nb_line      ,
		       uint32_t ** dcache_dedicated_size_line    ,
		       uint32_t ** dcache_dedicated_size_word    ,
		       uint32_t ** dcache_dedicated_associativity,
		       uint32_t ** dcache_dedicated_hit_latence  ,
		       uint32_t ** dcache_dedicated_miss_penality,
		       uint32_t    cache_shared_nb_level         ,
// 		       uint32_t    cache_shared_nb_port          ,
		       uint32_t  * cache_shared_nb_line          ,
		       uint32_t  * cache_shared_size_line        ,
		       uint32_t  * cache_shared_size_word        ,
		       uint32_t  * cache_shared_associativity    ,
		       uint32_t  * cache_shared_hit_latence      ,
		       uint32_t  * cache_shared_miss_penality    )
    {
      this->nb_cache_dedicated = nb_cache_dedicated;

      if (nb_cache_dedicated == 0)
	{
	  std::cerr << "[  ERROR  ] nb_cache_dedicated > 0" << std::endl;
	  exit(0);
	}

      uint32_t cache_shared_nb_port = 0;
      nb_iport = 0;
      nb_dport = 0;

      for (uint32_t i=0; i<nb_cache_dedicated; i++)
	{
	  nb_iport             += icache_dedicated_nb_port [i];
	  nb_dport             += dcache_dedicated_nb_port [i];
	  cache_shared_nb_port += icache_dedicated_nb_port [i];
	  cache_shared_nb_port += dcache_dedicated_nb_port [i];
	}

      param_cache_shared = new cache_multilevel::Parameters
	(cache_shared_nb_level         ,
	 cache_shared_nb_port          ,
	 cache_shared_nb_line          ,
	 cache_shared_size_line        ,
	 cache_shared_size_word        ,
	 cache_shared_associativity    ,
	 cache_shared_hit_latence      ,
	 cache_shared_miss_penality    );

      param_icache_dedicated = new cache_multilevel::Parameters * [nb_cache_dedicated];
      param_dcache_dedicated = new cache_multilevel::Parameters * [nb_cache_dedicated];

      for (uint32_t i=0; i<nb_cache_dedicated; i++)
	{
	  param_icache_dedicated [i] = new cache_multilevel::Parameters 
	    (icache_dedicated_nb_level      [i],
	     icache_dedicated_nb_port       [i],
	     icache_dedicated_nb_line       [i],
	     icache_dedicated_size_line     [i],
	     icache_dedicated_size_word     [i],
	     icache_dedicated_associativity [i],
	     icache_dedicated_hit_latence   [i],
	     icache_dedicated_miss_penality [i]);

	  param_dcache_dedicated [i] = new cache_multilevel::Parameters 
	    (dcache_dedicated_nb_level      [i],
	     dcache_dedicated_nb_port       [i],
	     dcache_dedicated_nb_line       [i],
	     dcache_dedicated_size_line     [i],
	     dcache_dedicated_size_word     [i],
	     dcache_dedicated_associativity [i],
	     dcache_dedicated_hit_latence   [i],
	     dcache_dedicated_miss_penality [i]);
	}
    }
    
  public : ~Parameters (void)
    {
      for (uint32_t i=0; i<nb_cache_dedicated; i++)
	{
	  delete param_icache_dedicated [i]; 
	  delete param_dcache_dedicated [i]; 
	}
      delete [] param_icache_dedicated;
      delete [] param_dcache_dedicated;
      delete    param_cache_shared;
    }
    
  public : std::string print (uint32_t depth)
    {
      std::string tab (depth,'\t');
      std::stringstream str ("");

      str << tab << "* Nb Cache dedicated    : " << nb_cache_dedicated << std::endl
	  << tab << "* Nb iport              : " << nb_iport << std::endl
	  << tab << "* Nb dport              : " << nb_dport << std::endl
;

      for (uint32_t i=0; i<nb_cache_dedicated; i++)
	str << tab << "  * ICACHE DEDICATED " << i << std::endl
	    << param_icache_dedicated [i]->print(depth+1) << std::endl;

      for (uint32_t i=0; i<nb_cache_dedicated; i++)
	str << tab << "  * DCACHE DEDICATED " << i << std::endl
	    << param_dcache_dedicated [i]->print(depth+1) << std::endl;

      str << tab << "  * CACHE SHARED" << std::endl;
      str << param_cache_shared->print(depth+1) << std::endl; 
           
      return str.str();
    }
    
    friend std::ostream& operator<< (std::ostream& output, Parameters &x)
    {
      output << x.print(0);
      return output;
    }
  };

};
};
#endif
