#ifndef ENVIRONMENT_PARAMETERS_H
#define ENVIRONMENT_PARAMETERS_H

#include "../Cache/include/Cache_Parameters.h"
#include "../Data/include/Data_Parameters.h"
#include "../Queue/include/Parameters.h"
#include "../TTY/include/TTY_Parameters.h"
#include "../RamLock/include/RamLock_Parameters.h"
#include "../Sim2OS/include/Sim2OS_Parameters.h"
#include "../../processor/Morpheo/Common/include/ToString.h"

namespace environment {

  class Parameters
  {
  public : uint32_t                nb_iport                ;
  public : uint32_t                nb_dport                ;
  public : uint32_t                nb_entity               ;
  public : uint32_t              * icache_dedicated_nb_port; //[nb_entity]
  public : uint32_t              * dcache_dedicated_nb_port; //[nb_entity]
                               
  public : uint32_t              * iaccess_nb_context      ; //[nb_entity]
  public : uint32_t              * iaccess_nb_packet       ; //[nb_entity]
  public : uint32_t              * iaccess_size_address    ; //[nb_entity]
  public : uint32_t              * iaccess_nb_instruction  ; //[nb_entity]
  public : uint32_t              * iaccess_size_instruction; //[nb_entity]
                               
  public : uint32_t              * daccess_nb_context      ; //[nb_entity]
  public : uint32_t              * daccess_nb_packet       ; //[nb_entity]
  public : uint32_t              * daccess_size_address    ; //[nb_entity]
  public : uint32_t              * daccess_size_data       ; //[nb_entity]

    // Parameters cache
  public : cache::Parameters     * param_cache             ;
    // Parameters tty
  public : uint32_t                nb_component_tty        ;
  public : uint32_t              * tty_address             ; //[nb_component_tty]
  public : tty::Parameters      ** param_tty               ; //[nb_component_tty]
    // Parameters ramlock
  public : uint32_t                nb_component_ramlock    ;
  public : uint32_t              * ramlock_address         ; //[nb_component_ramlock]
  public : ramlock::Parameters  ** param_ramlock           ; //[nb_component_ramlock]
    // Parameters sim2OS
  public : uint32_t                sim2os_address          ;
  public : uint32_t                sim2os_size             ;
  public : sim2os::Parameters    * param_sim2os            ;
    // Parameters data
  public : data::Parameters      * param_data              ;

    // Parameters buffer_respons
  public : queue::Parameters    ** param_buffer_irsp       ; //[nb_entity]
  public : queue::Parameters    ** param_buffer_drsp       ; //[nb_entity]

  public : Parameters (// General
		       uint32_t    nb_cache_dedicated,
		       
		       uint32_t  * iaccess_nb_context,
		       uint32_t  * iaccess_nb_instruction,
		       uint32_t  * iaccess_nb_packet,
		       uint32_t  * iaccess_size_address,
		       uint32_t  * iaccess_size_instruction,

		       uint32_t  * daccess_nb_context,
		       uint32_t  * daccess_nb_packet,
		       uint32_t  * daccess_size_address,
		       uint32_t  * daccess_size_data,

		       // buffer
		       uint32_t  * buffer_irsp_size,
		       uint32_t  * buffer_drsp_size,
		       
		       // Cache
		       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    ,

		       // TTY
		       uint32_t       nb_component_tty,
		       uint32_t     * tty_address,
		       uint32_t     * nb_tty,
		       std::string ** name_tty,
		       bool           with_xtty,

		       // RAMLOCK
		       uint32_t       nb_component_ramlock,
		       uint32_t     * ramlock_address,
		       uint32_t     * nb_lock,

		       // SIM2OS
		       uint32_t       sim2os_address,
		       uint32_t       sim2os_size,
		       SOCLIB_SEGMENT_TABLE * segment_table
		       )
    {
      this->nb_entity                = nb_cache_dedicated;

      this->icache_dedicated_nb_port = icache_dedicated_nb_port;
      this->dcache_dedicated_nb_port = dcache_dedicated_nb_port;

      this->iaccess_nb_context       = iaccess_nb_context      ;
      this->iaccess_nb_instruction   = iaccess_nb_instruction  ;
      this->iaccess_nb_packet        = iaccess_nb_packet       ;
      this->iaccess_size_address     = iaccess_size_address    ;
      this->iaccess_size_instruction = iaccess_size_instruction;
      this->daccess_nb_context       = daccess_nb_context      ;
      this->daccess_nb_packet        = daccess_nb_packet       ;
      this->daccess_size_address     = daccess_size_address    ;
      this->daccess_size_data        = daccess_size_data       ;

      param_cache = new cache::Parameters
	(nb_cache_dedicated            ,
	 icache_dedicated_nb_level     ,
	 icache_dedicated_nb_port      ,
	 icache_dedicated_nb_line      ,
	 icache_dedicated_size_line    ,
	 icache_dedicated_size_word    ,
	 icache_dedicated_associativity,
	 icache_dedicated_hit_latence  ,
	 icache_dedicated_miss_penality,
	 dcache_dedicated_nb_level     ,
	 dcache_dedicated_nb_port      ,
	 dcache_dedicated_nb_line      ,
	 dcache_dedicated_size_line    ,
	 dcache_dedicated_size_word    ,
	 dcache_dedicated_associativity,
	 dcache_dedicated_hit_latence  ,
	 dcache_dedicated_miss_penality,
	 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    
	 );

      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];
	}

      this->nb_component_tty = nb_component_tty;
      this->tty_address      = tty_address;
      
      param_tty = new tty::Parameters * [nb_component_tty];
      for (uint32_t i=0; i<nb_component_tty; i++)
	{
	  uint32_t tty_size = nb_tty [i] * 16; // 4 32bit-register by tty

// 	  std::ostringstream str("");
// 	  str << "tty_" << i;
	  segment_table->addSegment("tty",tty_address[i],tty_size,0,0,true);

	  param_tty [i] = new tty::Parameters (nb_tty    [i],
					       name_tty  [i],
					       with_xtty    );
	}

      this->nb_component_ramlock = nb_component_ramlock;
      this->ramlock_address      = ramlock_address;
      
      param_ramlock = new ramlock::Parameters * [nb_component_ramlock];
      for (uint32_t i=0; i<nb_component_ramlock; i++)
	{
	  uint32_t ramlock_size = nb_lock[i]; // registre 8 bits because it's min size access
// 	  std::ostringstream str ("");
// 	  str << "ramlock" << i;
	  segment_table->addSegment("ramlock",ramlock_address[i],ramlock_size,0,0,true);

	  param_ramlock [i] = new ramlock::Parameters (nb_lock [i]);
	}

      this->sim2os_address       = sim2os_address      ;
      this->sim2os_size          = sim2os_size         ;

      segment_table->addSegment("sim2os",sim2os_address,sim2os_size,0,0,true);
      param_sim2os = new sim2os::Parameters (segment_table);

      param_data   = new data::Parameters (16,0,0, segment_table);

      param_buffer_irsp = new queue::Parameters * [nb_entity];
      for (uint32_t i=0; i<nb_entity; i++)
	param_buffer_irsp [i] = new queue::Parameters (buffer_irsp_size [i]);

      param_buffer_drsp = new queue::Parameters * [nb_entity];
      for (uint32_t i=0; i<nb_entity; i++)
	param_buffer_drsp [i] = new queue::Parameters (buffer_drsp_size [i]);
    }

  public : ~Parameters (void)
    {
      for (uint32_t i=0; i<nb_entity; i++)
	delete param_buffer_irsp [i];
      delete [] param_buffer_irsp;

      for (uint32_t i=0; i<nb_entity; i++)
	delete param_buffer_drsp [i];
      delete [] param_buffer_drsp;

      delete param_data  ;
      delete param_sim2os;
      for (uint32_t i=0; i<nb_component_ramlock; i++)
	delete param_ramlock [i];
      delete [] param_ramlock;
      for (uint32_t i=0; i<nb_component_tty; i++)
	delete param_tty [i];
      delete [] param_tty;
      delete param_cache;
    }

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

      str+=tab+"nb_entity                    : "+morpheo::toString(nb_entity)+"\n";
      str+=tab+"nb_iport                     : "+morpheo::toString(nb_iport )+"\n";
      str+=tab+"nb_dport                     : "+morpheo::toString(nb_dport )+"\n";
      for (uint32_t i=0; i<nb_entity; ++i)
        {
      str+=tab+"ENTITY ["+morpheo::toString(i)+"]\n";
      str+=tab+"  * icache_dedicated_nb_port : "+morpheo::toString(icache_dedicated_nb_port[i])+"\n";
      str+=tab+"  * dcache_dedicated_nb_port : "+morpheo::toString(dcache_dedicated_nb_port[i])+"\n";
      str+=tab+"  * iaccess_nb_context       : "+morpheo::toString(iaccess_nb_context      [i])+"\n";
      str+=tab+"  * iaccess_nb_packet        : "+morpheo::toString(iaccess_nb_packet       [i])+"\n";
      str+=tab+"  * iaccess_size_address     : "+morpheo::toString(iaccess_size_address    [i])+"\n";
      str+=tab+"  * iaccess_nb_instruction   : "+morpheo::toString(iaccess_nb_instruction  [i])+"\n";
      str+=tab+"  * iaccess_size_instruction : "+morpheo::toString(iaccess_size_instruction[i])+"\n";
      str+=tab+"  * daccess_nb_context       : "+morpheo::toString(daccess_nb_context      [i])+"\n";
      str+=tab+"  * daccess_nb_packet        : "+morpheo::toString(daccess_nb_packet       [i])+"\n";
      str+=tab+"  * daccess_size_address     : "+morpheo::toString(daccess_size_address    [i])+"\n";
      str+=tab+"  * daccess_size_data        : "+morpheo::toString(daccess_size_data       [i])+"\n";
        }

      str+=tab+"CACHE\n";
      str+=param_cache->print(depth+1);

//       str+=tab+"nb_component_tty             : "+morpheo::toString(nb_component_tty           )+"\n";
//       for (uint32_t i=0; i<nb_component_tty; ++i)
//         {
//       str+=tab+"TTY ["+morpheo::toString(i)+"]\n";
//       str+=tab+"  * tty_address              : "+morpheo::toString(tty_address             [i])+"\n";
//       str+=param_tty->print(depth+1);
//         }      

//       str+=tab+"nb_component_ramlock         : "+morpheo::toString(nb_component_ramlock       )+"\n";
//       for (uint32_t i=0; i<nb_component_ramlock; ++i)
//         {
//       str+=tab+"RAMLOCK ["+morpheo::toString(i)+"]\n";
//       str+=tab+"  * ramlock_address          : "+morpheo::toString(ramlock_address         [i])+"\n";
//       str+=param_ramlock->print(depth+1);
//         }      

//       str+=tab+"SIM2OS\n";
//       str+=tab+"sim2os_address               : "+morpheo::toString(sim2os_address)+"\n";
//       str+=tab+"sim2os_size                  : "+morpheo::toString(sim2os_size   )+"\n";
//       str+=param_sim2os->print(depth+1);

//       str+=tab+"DATA\n";
//       str+=param_data->print(depth+1);

//       for (uint32_t i=0; i<nb_entity; ++i)
//         {
//       str+=tab+"BUFFER_IRSP ["+morpheo::toString(i)+"]\n";
//       str+=param_buffer_irsp[i]_data->print(depth+1);
//         }

//       for (uint32_t i=0; i<nb_entity; ++i)
//         {
//       str+=tab+"BUFFER_DRSP ["+morpheo::toString(i)+"]\n";
//       str+=param_buffer_drsp[i]_data->print(depth+1);
//         }

      return str;
    }

//   public : friend std::ostream& operator<< (std::ostream& output, const Parameters &x)
//     {
//       x.print(0);
//       return output;
//     }
  };

};
#endif
